[ZJOI2012]灾难
OJ题号:BZOJ2815、洛谷2597
思路:
先将所有的“生产者”连接至0号点“太阳”,然后用kahn求拓扑序。 、
易证一种生物会灭绝当且仅当他的所有食物均灭绝,
而所有食物均灭绝当且仅当他们的LCA灭绝。
按照拓扑序依次将各点加入新图,同时求该点所有食物的LCA,将该点作为LCA的儿子。
DFS遍历求各点后代数量。
注意倍增时不能直接循环到logN,而要循环到log2(dep)。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<queue> 5 #include<cmath> 6 inline int getint() { 7 int ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=65535,logN=17; 14 std::vector<int> c[N],p[N]; 15 std::queue<int> top; 16 int anc[N][logN]={0},dep[N]={0},in[N]={0}; 17 void kahn(const int x) { 18 std::queue<int> q; 19 q.push(x); 20 while(!q.empty()) { 21 int v=q.front(); 22 q.pop(); 23 top.push(v); 24 for(unsigned int i=0;i<c[v].size();i++) { 25 if(!--in[c[v][i]]) q.push(c[v][i]); 26 } 27 } 28 top.pop(); 29 } 30 std::vector<int> newc[N]; 31 inline void swap(int &a,int &b) { 32 int t; 33 t=a; 34 a=b; 35 b=t; 36 } 37 inline int LCA(int a,int b) { 38 if(dep[a]<dep[b]) swap(a,b); 39 for(int i=(int)log2(dep[a]);i>=0;i--) { 40 if(dep[a]-(1<<i)>=dep[b]) a=anc[a][i]; 41 } 42 if(a==b) return a; 43 for(int i=(int)log2(dep[a]);i>=0;i--) { 44 if(anc[a][i]!=anc[b][i]) a=anc[a][i],b=anc[b][i]; 45 } 46 return anc[a][0]; 47 } 48 int ans[N]={0}; 49 void getans(const int x) { 50 for(unsigned int i=0;i<newc[x].size();i++) { 51 getans(newc[x][i]); 52 ans[x]+=ans[newc[x][i]]+1; 53 } 54 } 55 int main() { 56 int n=getint(); 57 for(int i=1;i<=n;i++) { 58 for(int x=getint();x;x=getint()) { 59 p[i].push_back(x); 60 c[x].push_back(i); 61 in[i]++; 62 } 63 if(!p[i].size()) { 64 c[0].push_back(i); 65 p[i].push_back(0); 66 in[i]=1; 67 } 68 } 69 kahn(0); 70 while(top.size()) { 71 int v=top.front(); 72 top.pop(); 73 int lca=p[v][0]; 74 for(unsigned int i=1;i<p[v].size();i++) lca=LCA(lca,p[v][i]); 75 newc[lca].push_back(v); 76 anc[v][0]=lca,dep[v]=dep[lca]+1; 77 for(int i=1;i<=(int)log2(dep[v]);i++) anc[v][i]=anc[anc[v][i-1]][i-1]; 78 } 79 getans(0); 80 for(int i=1;i<=n;i++) printf("%d\n",ans[i]); 81 return 0; 82 }