bzoj 2815 [ZJOI2012]灾难(构造,树形DP)
【题意】
求把每个点删除后,不可达点的数目。
【思路】
构造一棵“灭绝树”,要求这棵树满足如果删除根节点后则该子树内的所有结点都不可达。则答案为子树大小-1。
如何构造这棵“灭绝树”?
将原图拓扑排序。当我们处理u的时候保证对u的所有食物已经建好树。引入0号节点,以之为所有生产者的食物。设u的食物为v[0..k],当我们至少把v[0..k]的LCA删掉之后u会灭绝,因此由LCA向u连边。增量构造LCA所需信息dep,fa。
鉴于写dfs的时候发生了一些奇奇怪怪的事(包括卡了下bzoj的评测机 lol,就把dfs改成了bfs
【题解链接】
http://fanhq666.blog.163.com/blog/static/8194342620124274154996/
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i,f) for(int i=front[u][f];i;i=e[i][f].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 1e5+10; 15 const int M = 2e6+10; 16 const int D = 21; 17 18 ll read() { 19 char c=getchar(); 20 ll f=1,x=0; 21 while(!isdigit(c)) { 22 if(c=='-') f=-1; c=getchar(); 23 } 24 while(isdigit(c)) 25 x=x*10+c-'0',c=getchar(); 26 return x*f; 27 } 28 29 struct Edge { 30 int v,nxt; 31 }e[M][2]; 32 int en[2]={1,1},front[N][2]; 33 void adde(int u,int v,int f) 34 { 35 e[++en[f]][f]=(Edge){v,front[u][f]}; front[u][f]=en[f]; 36 } 37 38 int n; 39 int in[N],fa[N][D],dep[N],siz[N]; 40 queue<int> q; 41 vector<int> tp; 42 43 void topo() 44 { 45 FOR(i,1,n) if(!in[i]) 46 q.push(i); 47 while(!q.empty()) { 48 int u=q.front(); q.pop(); 49 tp.push_back(u); 50 trav(u,i,0) { 51 int v=e[i][0].v; 52 if(!(--in[v])) { 53 q.push(v); 54 } 55 } 56 } 57 } 58 int lca(int u,int v) 59 { 60 if(u==-1) return v; 61 if(dep[u]<dep[v]) swap(u,v); 62 int t=dep[u]-dep[v]; 63 FOR(i,0,D-1) 64 if(t&(1<<i)) u=fa[u][i]; 65 if(u==v) return u; 66 for(int i=D-1;i>=0;i--) 67 if(fa[u][i]!=fa[v][i]) 68 u=fa[u][i],v=fa[v][i]; 69 return fa[u][0]; 70 } 71 void build_tree() 72 { 73 for(int i=tp.size()-1;i>=0;i--) { 74 int u=tp[i]; 75 int lc=-1; 76 trav(u,i,0) 77 lc=lca(lc,e[i][0].v); 78 lc=lc==-1?0:lc; 79 adde(lc,u,1); 80 dep[u]=dep[lc]+1; 81 fa[u][0]=lc; 82 FOR(i,1,D-1) fa[u][i]=fa[fa[u][i-1]][i-1]; 83 } 84 } 85 int vis[N]; 86 void getans(int u,int fa) 87 { 88 tp.clear(); 89 q.push(0); 90 while(!q.empty()) { 91 int u=q.front(); q.pop(); 92 tp.push_back(u); 93 trav(u,i,1) { 94 int v=e[i][1].v; 95 if(!vis[v]) 96 vis[v]=1,q.push(v); 97 } 98 } 99 for(int i=tp.size()-1;i>=0;i--) { 100 int u=tp[i]; 101 siz[u]=1; 102 trav(u,i,1) 103 siz[u]+=siz[e[i][1].v]; 104 } 105 } 106 int main() 107 { 108 //freopen("in.in","r",stdin); 109 //freopen("out.out","w",stdout); 110 n=read(); 111 int x; 112 FOR(i,1,n) { 113 while(x=read(),x) { 114 adde(i,x,0); in[x]++; 115 } 116 } 117 topo(); 118 build_tree(); 119 getans(0,-1); 120 FOR(i,1,n) printf("%d\n",siz[i]-1); 121 return 0; 122 }
posted on 2016-03-18 09:51 hahalidaxin 阅读(259) 评论(0) 编辑 收藏 举报