山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

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编辑  收藏  举报