1 条题解
-
0
对于原图所有入度为的结点,从结点到该结点连边。
定义结点的结点满足如下条件:存在到的至少一条路径,且不存在结点,使得删去后点不可不可到达。连接所有到,可以构成一棵树。由于原图有向无环,只与的前驱有关。在连接所有到构成的树上,原图中所有前驱在树上的即为。
#include<bits/stdc++.h> using namespace std; using PII=std::pair<int,int>; using i64=long long; struct Tree{ int n; std::vector<int> stk,tpn; std::vector<std::vector<int>> g1,g2,tr; std::vector<std::array<int,17>> fth; std::vector<int> in,dep,fa,siz; Tree(int num){ init(num); } void init(int num){ this->n=num-1; stk.clear(); tpn.clear(); g1.assign(num,{}); g2.assign(num,{}); tr.assign(num,{}); fth.assign(num,std::array<int,17>()); in.assign(num,0); dep.assign(num,0); fa.assign(num,-1); siz.assign(n+1,0); } void add(int u,int v){ g1[u].push_back(v); in[v]++; g2[v].push_back(u); } void topo(){ stk.push_back(0); for(int i=1;i<=n;i++){ if(in[i]!=0)continue; g1[0].push_back(i); g2[i].push_back(0); in[i]++; } while(stk.size()){ auto u=stk.back();; stk.pop_back(); tpn.push_back(u); for(auto v:g1[u]){ in[v]--; if(in[v]==0)stk.push_back(v); } } } int lca(int u,int v){ if(dep[u]<dep[v])std::swap(u,v); for(int i=16;i>=0;i--){ if(dep[fth[u][i]]>=dep[v]){ u=fth[u][i]; } } if(u==v)return u; for(int i=16;i>=0;i--){ if(fth[u][i]!=fth[v][i]){ u=fth[u][i]; v=fth[v][i]; } } return fth[u][0]; } void build(){ topo(); for(int i=1;i<=n;i++){ int u=tpn[i],v=g2[u][0]; for(int j=1;j<g2[u].size();j++){ v=lca(v,g2[u][j]); } tr[v].push_back(u); fa[u]=v; dep[u]=dep[v]+1; fth[u][0]=v; for(int i=1;i<=16;i++){ fth[u][i]=fth[fth[u][i-1]][i-1]; } } } void dfs(int u=0){ siz[u]=1; for(auto v:tr[u]){ dfs(v); siz[u]+=siz[v]; } } }; void solve(){ int n;std::cin>>n; Tree tr(n+1); for(int i=1;i<=n;i++){ int x;std::cin>>x; while(x--){ int y;std::cin>>y; tr.add(y,i); } } tr.build(); tr.dfs(); for(int i=1;i<=n;i++){ std::cout<<tr.siz[i]<<'\n'; } } signed main(){ std::cin.tie(nullptr); std::ios::sync_with_stdio(false); std::cout<<std::fixed<<std::setprecision(10); solve(); return 0; }
- 1
信息
- ID
- 258
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 10
- 已通过
- 2
- 上传者