题解 P5157 【[USACO18DEC]The Cow Gathering P】

· · 题解

看到这道题我们自然而然地就会想到拓扑。但是拓扑的时候不能满足题目的第二个条件:必须满足奶牛 Ai 要比奶牛 Bi 先离开。那我们就先按照 M 行的数据建个单向边,然后等会刷拓扑的时候一起刷,这样就能保证 Ai 要先比 Bi 刷到,也就是先离开。等我们找到第一个入度为 0 的点时,我们就找到了树根。接下来我们从树根开始反推,比如限定条件的 (A,B) ,那么 A 所在的子树(包括 A )都必须先处理掉,因为这帮家伙都不可能最后删除,那么剩下的都是可零可一的节点。按照题目的要求,那么我们绝对要全给 1 啊。

```cpp #include<bits/stdc++.h> #define TT 200000 using namespace std; const int maxn=100005,maxe=200005; int n,m,fa,hed,til,tot[2],du[maxn],ans[maxn],que[maxe],son[2][maxe],lnk[2][maxn],nxt[2][maxe]; bool vis[maxn]; inline int read(){ int ret=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch))ret=ret*10+ch-'0',ch=getchar(); return ret*f; } void add_e(int k,int x,int y){du[y]++;son[k][++tot[k]]=y;nxt[k][tot[k]]=lnk[k][x];lnk[k][x]=tot[k];} void Topu(){ for(int i=1;i<=n;i++)if(du[i]==1)que[++til]=i; while(hed<=til){ hed=(hed+1)%TT; if(du[que[hed]]==0){fa=que[hed];return ;} for(int j=lnk[0][que[hed]];j;j=nxt[0][j])if(--du[son[0][j]]==1)que[til=(til+1)%TT]=son[0][j]; for(int j=lnk[1][que[hed]];j;j=nxt[1][j])if(--du[son[1][j]]==1)que[til=(til+1)%TT]=son[1][j]; } } void dfs(int x,int father){ ans[x]=1; for(int j=lnk[0][x];j;j=nxt[0][j]){ if(son[0][j]==father||vis[son[0][j]])continue; dfs(son[0][j],x); } } int main(){ n=read();m=read(); for(int i=1;i<n;i++){ int x=read(),y=read(); add_e(0,x,y);add_e(0,y,x); }//建双向边 for(int i=1;i<=m;i++){ int x=read(),y=read(); add_e(1,x,y); vis[x]=1; }//再建图 Topu();//找树根 dfs(fa,0);//从根上开始遍历 for(int i=1;i<=n;i++)printf("%d\n",ans[i]);//输出答案 return 0; } ```