luogu P2597 [ZJOI2012]灾难

笑着哭i 提交于 2019-12-01 10:19:37

这道题好仙啊,不过暴力都能拿70pts。

考虑每个点的贡献,会发现,它只对它所有食物的LCA及LCA到根的路径上的节点有灾难值为一的贡献。

然后就是建树啦,我们必须保证当前节点的所有食物都已建好树,所以top_sort,在更新入度到为零时,就求出它所有食物的LCA,

然后将LCA做为此节点的父节点,并令sum(lca)++,更新ST表。。。

最后还要统计节点对LCA到根的节点的贡献,做一次树上前缀和即可。这个玩意什么时候叫做树上前缀和了QAQ。。其实特别low。

代码较丑,搞了三个链式前向星,最后还因为超级源点的深度和生产者的深度都赋成了1卡了半天。。。。

Code:

#include<iostream>
#include<cstdio>
#include<queue>
#define N 100000
using namespace std;
queue<int> q;
int n,Head[N],ver[N],nex[N],du[N],f[N][21],d[N],tot,sum[N];
int Head2[N],ver2[N],nex2[N],tot2;
int Head3[N],ver3[N],nex3[N],tot3;
inline int read(){
    char c=getchar();int x=0,flag=1;
    while(c<'0' || c>'9'){if(c=='-') flag=-1;c=getchar();}
    while(c>='0' && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x*flag;
}
void add(int x,int y){ver[++tot]=y;nex[tot]=Head[x];Head[x]=tot;}
void add2(int x,int y){ver2[++tot2]=y;nex2[tot2]=Head2[x];Head2[x]=tot2;}
void add3(int x,int y){ver3[++tot3]=y;nex3[tot3]=Head3[x];Head3[x]=tot3;}
int LCA(int x,int y){
    if(d[x]<d[y]) swap(x,y);
    for(int i=20;i>=0;i--) if(d[f[x][i]]>=d[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
void dfs(int x){
    sum[x]=1;
    for(int i=Head3[x];i;i=nex3[i]){
        int y=ver3[i];dfs(y);
        sum[x]+=sum[y];
    }
}
void top_sort(){
    for(int i=1;i<=n;i++) if(!du[i]) add(0,i),add2(i,0);
    q.push(0);
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=Head[x];i;i=nex[i]){
            int y=ver[i];du[y]--;
            if(du[y]<=0){
                int lca=x;
                for(int j=Head2[y];j;j=nex2[j]){
                    int k=ver2[j];if(k==x) continue;
                    lca=LCA(lca,k);
                }
                f[y][0]=lca;d[y]=d[lca]+1;add3(lca,y);
                for(int k=1;k<=20;k++) f[y][k]=f[f[y][k-1]][k-1];
                q.push(y);
            }
        }
    }
}
int main(){
    n=read();d[0]=1;
    for(int i=1;i<=n;i++){
        int x;
        while(scanf("%d",&x) && x){add(x,i);add2(i,x);du[i]++;}
    }
    top_sort();dfs(0);
    for(int i=1;i<=n;i++) printf("%d\n",sum[i]-1);
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!