E. Plan of Lectures(給定拓撲圖求輸出序列滿足存在給定鏈)
阿新 • • 發佈:2020-12-19
題:https://codeforces.com/contest/1463/problem/E
題意:給定拓撲圖,在給定鏈(以邊的形式給出),問是否能在拓撲順序中找出一個序列使得這個序列包含給定的鏈(x->y->z)。
分析:
給定的拓撲圖我們可以當作一個DAG,然後給定的m個邊我們可以在原圖上進行縮點,縮成的點一定得是一條鏈;
判斷這些鏈會不會構成環;
構建新圖G,再判斷是否能構成拓撲序列,再把壓縮的點解壓出來
#include<bits/stdc++.h> using namespace std; #define pb push_back const int M=3e5+5;View Codeint p[M],vis[M],nex[M],in[M],rt[M],rnk[M],cmp[M]; vector<int>G[M],ans; queue<int>que; int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&p[i]); for(int u,v,i=1;i<=m;i++){ scanf("%d%d",&u,&v); nex[u]=v; vis[v]=1;///在不是鏈頭就標記 } int tot=0; for(int i=1;i<=n;i++){ if(vis[i]) continue; cmp[i]=++tot; int now=0,x=nex[i]; rnk[i]=now; rt[tot]=i; while(x!=0&&cmp[x]==0){ rnk[x]=++now; cmp[x]=tot; x=nex[x]; } }for(int i=1;i<=n;i++)///check circle if(!cmp[i]||(cmp[p[i]]==cmp[i]&&rnk[i]<rnk[p[i]])) return puts("0"),0; for(int i=1;i<=n;i++){///construct new graph if(p[i]==0) continue; if(cmp[i]!=cmp[p[i]]){ G[cmp[p[i]]].pb(cmp[i]); in[cmp[i]]++; } } ///tuopu for(int i=1;i<=tot;i++) if(in[i]==0) que.push(i); while(!que.empty()){ int u=que.front();que.pop(); ans.pb(u); for(auto v:G[u]) if(--in[v]==0) que.push(v); } if(ans.size()==tot){ for(auto v:ans){ int nowi=rt[v]; while(nowi!=0){ printf("%d ",nowi); nowi=nex[nowi]; } } } else puts("0"); return 0; }