《P2597 [ZJOI2012]灾难》
这里是个DAG,可以利用类似倍增的做法。
但是可以直接支配树做,建立一个虚点向所有的起点,然后支配树就即可。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 5e5 + 5; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e16 #define dbg(ax) cout << "now this num is " << ax << endl; int n,val[N],dfn[N],semi[N],idom[N],rk[N],fa[N],out[N],sz[N],tim = 0; vector<int> G[N],RG[N],T[N]; namespace Node{ int fa[N],val[N]; void init() { for(int i = 1;i <= n + 1;++i) fa[i] = i; } int Find(int x) { if(x == fa[x]) return x; int ffa = fa[x]; fa[x] = Find(fa[x]); if(dfn[semi[val[x]]] > dfn[semi[val[ffa]]]) val[x] = val[ffa]; return ffa; } void Merge(int x,int y) { x = Find(x),y = Find(y); fa[y] = x; } }; void dfs(int u) { dfn[u] = ++tim; rk[tim] = u; for(auto v : G[u]) { if(!dfn[v]) { fa[v] = u; dfs(v); } } } int getmin(int x,int y) { return dfn[x] < dfn[y] ? x : y; } void solve() { dfs(n + 1); dfn[0] = tim + 1; Node::init(); for(int i = n + 1;i >= 1;--i) { int x = rk[i]; for(auto v : RG[x]) { if(dfn[v] < dfn[x]) semi[x] = getmin(semi[x],v); else { Node::Find(v); semi[x] = getmin(semi[x],semi[Node::val[v]]); } } for(auto v : T[x]) { Node::Find(v); int ma = Node::val[v]; if(semi[ma] == x) idom[v] = x; else idom[v] = ma; } Node::val[x] = x; Node::Merge(fa[x],x); T[semi[x]].push_back(x); } for(int i = 2;i <= n + 1;++i) { int x = rk[i]; if(idom[x] != semi[x]) idom[x] = idom[idom[x]]; } for(int i = n + 1;i >= 2;--i) { int x = rk[i]; ++sz[x]; if(idom[x]) sz[idom[x]] += sz[x]; } } int main() { scanf("%d",&n); for(int i = 1;i <= n;++i) { int x; while(scanf("%d",&x),x != 0) { G[x].push_back(i); RG[i].push_back(x); out[i]++; } } for(int i = 1;i <= n;++i) { if(out[i] == 0) { G[n + 1].push_back(i); RG[i].push_back(n + 1); } } solve(); for(int i = 1;i <= n;++i) printf("%d\n",sz[i] - 1); system("pause"); return 0; }