BZOJ:2815: [ZJOI2012]灾难
题解:
构造灭绝树;
x指向的点表示x的祖先死亡则x死亡
动态LCA;
可以用LCT维护或直接更新倍增数组
最后统计子树点的个数
坑:
我还不会序列型Toposort
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn=100000; int n; vector<int>G[maxn]; vector<int>G2[maxn]; int cntedge; int head[maxn]; int to[maxn<<1],nex[maxn<<1]; int addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } int f[maxn][20]; int depth[maxn]; int Lcainit(int i,int fa){ f[i][0]=fa;depth[i]=depth[fa]+1; for(int j=1;j<=19;++j){ f[i][j]=f[f[i][j-1]][j-1]; } } int Getlca(int x,int y){ if(depth[x]<depth[y])swap(x,y); for(int j=19;j>=0;--j){ if(depth[f[x][j]]>=depth[y]){ x=f[x][j]; } } if(x==y)return x; for(int j=19;j>=0;--j){ if(f[x][j]!=f[y][j]){ x=f[x][j];y=f[y][j]; } } return f[x][0]; } int root; int indegree[maxn]; int sta[maxn],top; int lca[maxn]; int Toposort(){ for(int i=1;i<=n;++i){ if(indegree[i]==0){ sta[++top]=i; Lcainit(i,root); G2[root].push_back(i); } } while(top){ int x=sta[top--]; for(int i=head[x];i;i=nex[i]){ --indegree[to[i]]; if(indegree[to[i]]==0){ sta[++top]=to[i]; for(int j=0;j<G[to[i]].size();++j){ int v=G[to[i]][j]; if(lca[to[i]]==0){ lca[to[i]]=v; }else{ lca[to[i]]=Getlca(lca[to[i]],v); } } Lcainit(to[i],lca[to[i]]); G2[lca[to[i]]].push_back(to[i]); } } } } int siz[maxn]; int dfs(int now,int fa){ siz[now]=1; for(int i=0;i<G2[now].size();++i){ int v=G2[now][i]; if(v==fa)continue; dfs(v,now); siz[now]+=siz[v]; } } void minit(){ for(int i=1;i<=n+1;++i){ G[i].clear();G2[i].clear(); } cntedge=top=0; memset(head,0,sizeof(head)); memset(f,0,sizeof(f)); memset(indegree,0,sizeof(indegree)); memset(lca,0,sizeof(lca)); } int main(){ scanf("%d",&n); minit(); root=n+1;depth[root]=1; for(int i=1;i<=n;++i){ int x; scanf("%d",&x); while(x){ G[i].push_back(x); addedge(x,i); indegree[i]++; scanf("%d",&x); } } Toposort(); dfs(root,0); for(int i=1;i<=n;++i)printf("%d\n",siz[i]-1); return 0; }
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!