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;
}

  

posted @ 2018-01-02 21:46  ws_zzy  阅读(159)  评论(0编辑  收藏  举报