码迷,mamicode.com
首页 > 其他好文 > 详细

[ZJOI2012]灾难

时间:2017-07-12 12:06:34      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:pre   span   get   return   class   div   scanf   void   cpp   

题目:洛谷P2597、BZOJ2815(然而此处并没有题面)、codevs1210

题目大意:给你一个食物网,要你求每个生物的“毁灭值”(毁灭值为该生物灭绝后,其他跟着它灭绝的生物的总数)。

解题思路:拓扑排序+LCA。

先假设所有生产者都吃“太阳”,然后对它们进行拓扑排序。以拓扑序依次加点,每次将要加的点与所有父亲求LCA,此时LCA或LCA的任一父亲节点死亡,则该点灭绝。所以直接把该点变为LCA的子节点即可。此时每个节点的毁灭值为以它为根的子树的节点的个数。

不过我的代码在codevs上莫名的RE了,知道原因的可以告诉我。

C++ Code:

 

#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
int n;
vector<int>p[65536],c[65536],nc[65536];
queue<int>tp;
int has[65536],dep[65536],s[65536][18],ans[65536];
void topo(){
	queue<int>q;
	q.push(0);
	while(!q.empty()){
		int v=q.front();
		q.pop();
		tp.push(v);
		for(int i=0;i<c[v].size();i++)
		if(!--has[c[v][i]])q.push(c[v][i]);
	}
}
int LCA(int x,int y){
	int i,j;
	if(x==-1)return y;
	if(dep[x]<dep[y])swap(x,y);
	for(i=0;(1<<i)<=dep[x];i++);i--;
	for(j=i;j>-1;j--){
		if(dep[x]-(1<<j)>=dep[y])x=s[x][j];
	}
	if(x==y)return x;
	for(j=i;j>=0;j--)
	if(s[x][j]!=s[y][j])
	x=s[x][j],y=s[y][j];
	return s[x][0];
}
void getans(int x){
	for(int i=0;i<nc[x].size();i++){
		getans(nc[x][i]);
		ans[x]+=ans[nc[x][i]]+1;
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x;
		while(scanf("%d",&x),x){
			p[i].push_back(x);
			c[x].push_back(i);
			has[i]++;
		}
		if(!p[i].size()){
			p[i].push_back(0);
			c[0].push_back(i);
			has[i]=1;
		}
	}
	topo();
	while(!tp.empty()){
		int u=tp.front();tp.pop();
		int lca=-1;
		for(int i=0;i<p[u].size();i++)lca=LCA(lca,p[u][i]);
		nc[lca].push_back(u);
		s[u][0]=lca;
		dep[u]=dep[lca]+1;
		for(int i=1;(1<<i)<=dep[u];i++)s[u][i]=s[s[u][i-1]][i-1];
	}
	getans(0);
	for(int i=1;i<=n;i++)
	printf("%d\n",ans[i]);
	return 0;
}

 

  

 

[ZJOI2012]灾难

标签:pre   span   get   return   class   div   scanf   void   cpp   

原文地址:http://www.cnblogs.com/Mrsrz/p/7154508.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!