支配树裸题:求支配集
不太会写带权并查集,调了好久
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 #define maxn 100020 8 #define inf 0x3f3f3f3f 9 10 typedef long long ll; 11 struct node{ 12 int next,to; 13 void cl(){ 14 next = 0 , to = 0; 15 } 16 }e[maxn * 2],e2[maxn * 2]; 17 int head[maxn],head2[maxn],cnt; 18 int n,m,fa[maxn],val[maxn],vis[maxn]; 19 int idom[maxn],semi[maxn],pnt[maxn],dfn[maxn],id[maxn],dfstime; 20 ll ans[maxn]; 21 vector <int> ques[maxn]; 22 23 inline void clear(){ 24 for (int i = 1 ; i <= cnt ; i++) e[i].cl(); 25 for (int i = 1 ; i <= n ; i++) head[i] = 0; 26 cnt = 0; 27 for (int i = 1 ; i <= n ; i++) ques[i].clear(); 28 for (int i = 1 ; i <= n ; i++) ans[i] = 0 , id[i] = pnt[i] = fa[i] = idom[i] = semi[i] = val[i] = vis[i] = 0 , dfn[i] = inf; 29 dfstime = 0; 30 } 31 inline void adde(int x,int y){ 32 e[++cnt].to = y; 33 e2[cnt].to = x; 34 e[cnt].next = head[x]; 35 e2[cnt].next = head2[y]; 36 head[x] = cnt; 37 head2[y] = cnt; 38 } 39 inline void adde2(int x,int y){ 40 e[++cnt].to = y; 41 e[cnt].next = head[x]; 42 head[x] = cnt; 43 } 44 void dfs(int x){ 45 vis[x] = 1, dfn[x] = ++dfstime, id[dfstime] = x; 46 for (int i = head[x] ; i ; i = e[i].next){ 47 if ( !vis[e[i].to] ) pnt[e[i].to] = x , dfs(e[i].to); 48 } 49 } 50 int getfa(int x){ 51 if ( fa[x] == x ) return x; 52 int a = getfa(fa[x]); 53 if ( semi[val[x]] > semi[val[fa[x]]] ) val[x] = val[fa[x]]; 54 return fa[x] = a; 55 } 56 inline void merge(int x,int y){ 57 if ( getfa(x) != getfa(y) ) fa[y] = x; 58 } 59 void dfs(int x,int fa,ll cur){ 60 cur += (ll)x; 61 ans[x] = cur; 62 for (int i = head[x] ; i ; i = e[i].next){ 63 if ( e[i].to == fa ) continue; 64 dfs(e[i].to,x,cur); 65 } 66 } 67 void calc(){ 68 for (int i = 1 ; i <= cnt ; i++) e[i].cl(), e2[i].cl(); 69 for (int i = 1 ; i <= n ; i++) head[i] = head2[i] = 0; 70 cnt = 0; 71 for (int i = 1 ; i <= n ; i++){ 72 if ( idom[i] && idom[i] != i ) adde2(idom[i],i) , adde2(i,idom[i]); 73 } 74 dfs(n,0,0); 75 } 76 void solve(){ 77 semi[0] = inf; 78 //val[x]表示到x的祖先中semi最小的点的编号 79 //semi[x]表示x的半支配点的dfn 80 for (int i = 1 ; i <= n ; i++) fa[i] = i , semi[i] = inf; 81 for (int i = dfstime ; i ; i--){ 82 int x = id[i]; 83 for (int j = 0 ; j < ques[x].size() ; j++){ 84 int y = ques[x][j]; 85 getfa(y); 86 if ( semi[val[y]] < dfn[x] ) idom[y] = val[y]; 87 } 88 for (int j = head2[x] ; j ; j = e2[j].next){ 89 if ( dfn[x] > dfn[e2[j].to] ) semi[x] = min(semi[x],dfn[e2[j].to]); 90 else{ 91 getfa(e2[j].to); 92 semi[x] = min(semi[x],semi[val[e2[j].to]]); 93 } 94 } 95 if ( pnt[x] ) semi[x] = min(semi[x],dfn[pnt[x]]); 96 if ( x == n ) semi[x] = 1; 97 if ( semi[x] < semi[val[x]] ) val[x] = x; 98 for (int j = head[x] ; j ; j = e[j].next) 99 if ( pnt[e[j].to] == x ) merge(x,e[j].to); 100 ques[id[semi[x]]].push_back(x); 101 } 102 for (int i = 1 ; i <= dfstime ; i++){ 103 int x = id[i]; 104 if ( idom[x] ) idom[x] = idom[idom[x]]; //idom[x]最初存的是x到其semi路径上的semi最小值的点 105 else idom[x] = id[semi[x]]; 106 } 107 // for (int i = 1 ; i <= n ; i++) cout<<idom[i]<<" "; 108 // cout<<endl; 109 calc(); 110 for (int i = 1 ; i <= n ; i++){ 111 printf("%lld",ans[i]); 112 if ( i < n ) printf(" "); 113 } 114 printf("\n"); 115 } 116 int main(){ 117 freopen("input.txt","r",stdin); 118 while ( ~scanf("%d %d",&n,&m) ){ 119 clear(); 120 for (int i = 1 ; i <= m ; i++){ 121 int x,y; 122 scanf("%d %d",&x,&y); 123 adde(x,y); 124 } 125 dfs(n); 126 solve(); 127 } 128 }
时间: 2024-11-04 17:12:23