luogu P2597 [ZJOI2012]灾难
这道题好仙啊,不过暴力都能拿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); }