【[ZJOI2012]災難】
阿新 • • 發佈:2019-01-01
好像很久之前就看過這道題,大概是剛學\(LCA\)的時候
之後當時肯定是不會的呀
現在發現這道題並不是非常難
首先我們發現這個滅絕的關係非常像一棵樹,我們建出這個滅絕樹求一個字首和就可以啦
那麼應該怎麼建這棵樹呢
我們一邊拓撲排序一邊建樹,一個點的父親應該是其所有食物節點的\(lca\),於是一邊拓撲排序一邊求\(lca\)就好了
手滑了好幾次
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define re register #define maxn 70005 struct Edge { int v,nxt; }e[200005]; int head[maxn]; int num,n; inline void add_edge(int x,int y) { e[++num].v=y; e[num].nxt=head[x]; head[x]=num; } inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } int deep[maxn],f[maxn][18]; namespace Topsort { struct E { int v,nxt; }e[200005]; int num,head[maxn],r[maxn],q[maxn]; int fa[maxn]; inline void add(int x,int y) { e[++num].v=y; e[num].nxt=head[x]; head[x]=num; } inline int LCA(int x,int y) { if(deep[x]<deep[y]) std::swap(x,y); for(re int i=17;i>=0;--i) if(f[x][i]!=-1&&deep[f[x][i]]>=deep[y]) x=f[x][i]; if(x==y) return x; for(re int i=17;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } inline void init() { n=read(); int x; for(re int i=1;i<=n;i++) { x=read(); while(x) add(x,i),r[i]++,x=read(); } for(re int i=1;i<=n;i++) if(!r[i]) add(0,i),r[i]++; int tot=0; q[++tot]=0; memset(f,-1,sizeof(f)); memset(fa,-1,sizeof(fa)); for(re int i=1;i<=tot;i++) { for(re int j=head[q[i]];j;j=e[j].nxt) { r[e[j].v]--; if(fa[e[j].v]==-1) fa[e[j].v]=q[i]; else fa[e[j].v]=LCA(fa[e[j].v],q[i]); if(!r[e[j].v]) { add_edge(fa[e[j].v],e[j].v); deep[e[j].v]=deep[fa[e[j].v]]+1; f[e[j].v][0]=fa[e[j].v]; for(re int k=1;k<=17;k++) f[e[j].v][k]=f[f[e[j].v][k-1]][k-1]; q[++tot]=e[j].v; } } } } } int sz[maxn]; void dfs(int x) { sz[x]=1; for(re int i=head[x];i;i=e[i].nxt) if(deep[e[i].v]>deep[x]) { deep[e[i].v]=deep[x]+1; dfs(e[i].v); sz[x]+=sz[e[i].v]; } } int main() { Topsort::init(); dfs(0); for(re int i=1;i<=n;i++) printf("%d\n",sz[i]-1); return 0; }