版權說明:來自洛谷P3916html
給出$N$個點,$M$條邊的有向圖,對於每一個點$v$,求$A(v)$表示從點$v$出發,能到達的編號最大的點。ios
app
第1 行,2 個整數$N,M$。ide
接下來$M$行,每行2個整數$U_i,V_i$,表示邊$(U_i,V_i)$。點用$1, 2,\cdots,N$編號。spa
N 個整數$A(1),A(2),\cdots,A(N)$。code
• 對於60% 的數據,$1 \le N . K \le 10^3$;orm
• 對於100% 的數據,$1 \le N , M \le 10^5$。htm
首先在沒有處理前是有向有環圖,這樣咱們直接DFS是會超時的(固然聽說還有 DFS100次 玄學作法,可是不推薦)。咱們經過tarjan縮點後將其變爲有向無環圖,如圖blog
那麼後面的事情就很簡單了,咱們首先染色,繼承邊,再經過DFS獲得結果。固然你也能夠記憶化讓時間跑快一點。具體請看代碼繼承
1 #include<iostream> 2 #include<fstream> 3 #include<cstring> 4 #include<stack> 5 using namespace std; 6 const int Max_N=1e5+5; 7 const int Max_E=1e5+5; 8 9 int n,e; 10 int U[Max_E],V[Max_E],rem[Max_N]; 11 12 int tot; 13 int head[Max_N],Next[Max_E],to[Max_E]; 14 15 int Index; 16 stack<int>sta; 17 int DFN[Max_N],LOW[Max_N]; 18 bool vis[Max_N]; 19 20 int cnt; 21 int PoiV[Max_N],PoiP[Max_N]; 22 23 void Add_Edge(int u,int v) 24 { 25 Next[++tot]=head[u]; 26 head[u]=tot; 27 to[tot]=v; 28 // 前向星 29 return ; 30 } 31 void tarjan(int p) 32 { 33 vis[p]=1; 34 sta.push(p); 35 DFN[p]=LOW[p]=++Index; 36 register int i; 37 for(i=head[p];i^0;i=Next[i]){ 38 int u=p,v=to[i]; 39 if(!DFN[v]){ 40 tarjan(v); 41 LOW[u]=min(LOW[u],LOW[v]); 42 } 43 else if(vis[v]) 44 LOW[u]=min(LOW[u],DFN[v]); 45 } 46 // tarjan操做 47 if(DFN[p]==LOW[p]){ 48 int pos; 49 cnt++; 50 while(pos=sta.top()){ 51 sta.pop(); 52 vis[pos]=0; 53 PoiP[pos]=cnt; 54 PoiV[cnt]=max(PoiV[cnt],pos); 55 // 染色 56 if(pos==p) 57 break; 58 } 59 } 60 return ; 61 } 62 int DFS(int p) 63 { 64 if(rem[p]^-1) 65 return rem[p]; 66 rem[p]=PoiV[p]; 67 register int i; 68 for(i=head[i];i^0;i=Next[i]) 69 rem[p]=max(rem[p],DFS(to[i])); 70 // 記憶化搜索獲得答案 71 return rem[p]; 72 } 73 int main() 74 { 75 scanf("%d%d",&n,&e); 76 register int i,j; 77 for(i=1;i<=e;i++){ 78 scanf("%d%d",&U[i],&V[i]); 79 Add_Edge(U[i],V[i]); 80 } 81 for(i=1;i<=n;i++) 82 if(!DFN[i]) 83 tarjan(i); 84 // tarjan 85 tot=0; 86 memset(head,0,sizeof(head)); 87 // 清空邊 88 for(i=1;i<=e;i++) 89 if(PoiP[U[i]]^PoiP[V[i]]) 90 Add_Edge(PoiP[U[i]],PoiP[V[i]]); 91 // 這裏好好理解,繼承邊部分 92 memset(rem,-1,sizeof(rem)); 93 for(i=1;i<=cnt;i++) 94 DFS(i); 95 // 求出縮點後邊的答案 96 for(i=1;i<=n;i++){ 97 if(i>1) 98 printf(" "); 99 printf("%d",rem[PoiP[i]]); 100 } 101 // 輸出 102 return 0; 103 }