DZY Loves Topological Sorting
Problem Description
A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge (u→v) from vertex u to vertex v , u comes before v in the ordering.
Now, DZY has a directed acyclic graph(DAG). You should find the lexicographically largest topological ordering after erasing at most k
edges from the graph.
Input
The input consists several test cases. (TestCase≤5
)
The first line, three integers n,m,k(1≤n,m≤105,0≤k≤m)
.
Each of the next m
lines has two integers: u,v(u≠v,1≤u,v≤n)
, representing a direct edge(u→v)
.
Output
For each test case, output the lexicographically largest topological ordering.
Sample Input
5 5 2
1 2
4 5
2 4
3 4
2 3
3 2 0
1 2
1 3
Sample Output
5 3 1 2 4
1 3 2
Hint
Case 1.
Erase the edge (2->3),(4->5).
And the lexicographically largest topological ordering is (5,3,1,2,4).
题解:因为我们要求最后的拓扑序列字典序最大,所以一定要贪心地将标号越大的点越早入队。我们定义点ii的入度为d_id?i??。假设当前还能删去kk条边,那么我们一定会把当前还没入队的d_i\leq kd?i??≤k的最大的ii找出来,把它的d_id?i??条入边都删掉,然后加入拓扑序列。可以证明,这一定是最优的。
具体实现可以用线段树维护每个位置的d_id?i??,在线段树上二分可以找到当前还没入队的d_i\leq kd?i??≤k的最大的ii。于是时间复杂度就是\text{O}((n+m) \log n)O((n+m)logn).
///1085422276 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") using namespace std ; typedef long long ll; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){ if(ch==‘-‘)f=-1;ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘){ x=x*10+ch-‘0‘;ch=getchar(); }return x*f; } //**************************************** const int N=500000+50; #define mod 1000000007 #define inf 10000007 int ind[N],head[N],t,n,m,K,vis[N]; vector<int > ans; vector<int >G[N]; struct ss { int l,r,sum,index; }tr[N*5]; struct sss { int to,next; }e[N*2]; void init() { t=1;mem(head);mem(ind);ans.clear();mem(vis); for(int i=1;i<=n;i++)G[i].clear(); } void add(int u,int v) {e[t].to=v;e[t].next=head[u];head[u]=t++;} void build(int k,int s,int t) { tr[k].l=s;tr[k].r=t; if(s==t) { tr[k].sum=ind[s]; tr[k].index=s; return ; } int mid=(s+t)>>1; build(k<<1,s,mid); build(k<<1|1,mid+1,t); tr[k].sum=min(tr[k<<1].sum,tr[k<<1|1].sum); } int ask(int k,int s,int t,int c) { int ret; if(tr[k].l==tr[k].r&&tr[k].l==s) { return tr[k].index; } int mid=(tr[k].l+tr[k].r)>>1; if(tr[k<<1|1].sum<=c) { ret=ask(k<<1|1,mid+1,t,c); } else { ret=ask(k<<1,s,mid,c); } return ret; } void update(int k,int x,int c) { if(tr[k].l==tr[k].r&&tr[k].l==x) { tr[k].sum+=c; return ; } int mid=(tr[k].l+tr[k].r)>>1; if(x<=mid) update(k<<1,x,c); else update(k<<1|1,x,c); tr[k].sum=min(tr[k<<1].sum,tr[k<<1|1].sum); } int main() { while(scanf("%d%d%d",&n,&m,&K)!=EOF) { init();int u,v,check; for( int i=1;i<=m;i++) { scanf("%d%d",&u,&v); ind[v]++; G[u].pb(v); } build(1,1,n); for(int i=n;i>=1;i--) { check=ask(1,1,n,K); ans.pb(check); K-=ind[check]; update(1,check,inf); for(int j=0;j<G[check].size();j++) { update(1,G[check][j],-1); ind[G[check][j]]--; } } for(int i=0;i<ans.size()-1;i++) { printf("%d ",ans[i]); } printf("%d\n",ans[ans.size()-1]); } return 0; }
代码