P5157 The Cow Gathering [拓扑排序/树上差分]
给定 个节点的树, 有 条限制条件 : 比 先删除.
请输出 所有节点能否最后被删除.
- 找到任意一个满足条件的点
- 统计答案
- 向 连有向边
- 若存在 , 说明无解,
- 否则取出 , 即为一个满足条件的节点 .
以 为根建树 :
对于一颗子树, 设该节点为 ,
-
有连出去的 有向边.
以 为根节点的子树所有节点全部不能作为最后一个节点出去
-
没有连出去的 有向边 .
不操作
使用 树上差分, 以 为下标建立 ,
对于 , 同样 向 连一条有向边,
先使用 判环, 若有环说明 无解, 否则 :
此时分为三种情况 :
- 在 上方
- 在 上方
- 和 拥有 最近公共祖先
对于 和 , 直接将 进行差分操作,
对于 , 记 全局数组 , 将 ,
跳到 的正下方后 !!
进行 反差分操作.
最后根据 统计答案.
#include<bits/stdc++.h>
#define reg register
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 100005;
int N;
int M;
int num0;
int tot;
int flag;
int C[maxn];
int rd[maxn];
int dfn[maxn];
int dep[maxn];
int size[maxn];
int head[maxn];
int Fk[maxn][20];
bool Used[maxn];
struct Edge{ int nxt, to; } edge[maxn<<2];
void Add(int from, int to){
edge[++ num0] = (Edge){ head[from], to };
head[from] = num0;
}
void DFS(int k, int fa){
dfn[k] = ++ tot;
dep[k] = dep[fa] + 1;
size[k] = 1;
for(reg int i = 1; i <= 19; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
if(to == fa) continue ;
Fk[to][0] = k;
DFS(to, k);
size[k] += size[to];
}
}
int LCA(int a, int b){
if(dep[a] < dep[b]) std::swap(a, b);
for(reg int i = 19; i >= 0; i --)
if(dep[Fk[a][i]] >= dep[b]) a = Fk[a][i];
if(a == b) return a;
for(reg int i = 19; i >= 0; i --)
if(Fk[a][i] != Fk[b][i]) a = Fk[a][i], b = Fk[b][i];
return Fk[a][0];
}
bool chk(){
tot = 0;
std::queue <int> Q;
for(int i = 1; i <= N; i ++)
if(rd[i] == 1) Q.push(i), rd[i] --;
while(!Q.empty()){
int ft = Q.front(); Q.pop();
tot ++, rd[ft] --;
for(reg int i = head[ft]; i; i = edge[i].nxt){
int to = edge[i].to;
if(-- rd[to] == 1) Q.push(to);
}
}
if(tot < N) return 0;
return 1;
}
int jump(int a, int b){
for(reg int i = 19; i >= 0; i --)
if(dep[Fk[a][i]] > dep[b]) a = Fk[a][i];
return a;
}
int main(){
freopen("visit.in", "r", stdin);
freopen("visit.out", "w", stdout);
N = read();
M = read();
for(reg int i = 1; i < N; i ++){
int x = read(), y = read();
Add(x, y), Add(y, x);
rd[x] ++, rd[y] ++;
}
DFS(1, 0);
for(reg int i = 1; i <= M; i ++){
int a = read(), b = read();
Add(a, b), rd[b] ++;
int lca = LCA(a, b);
if(lca == a){ // a up b
int t = jump(b, a);
C[dfn[t]] --, C[dfn[t]+size[t]] ++;
flag ++;
}else if(lca != a && lca != b){ // a ^ b
C[dfn[a]] ++;
C[dfn[a]+size[a]] --;
}else if(lca == b){ // b up a
C[dfn[a]] ++;
C[dfn[a]+size[a]] --;
}
}
if(!chk()){
for(reg int i = 1; i <= N; i ++) printf("0\n");
return 0;
}else{
for(reg int i = 1; i <= N; i ++) C[i] += C[i-1];
for(reg int i = 1; i <= N; i ++)
if(C[dfn[i]]+flag > 0) printf("0\n");
else printf("1\n");
}
return 0;
}