T h e C o w G a t h e r i n g The\ Cow\ Gathering The Cow Gathering
D e s c r i p t i o n \mathcal{Description} Description
给定 N N N 个节点的树, 有 M M M 条限制条件 : a i a_i ai 比 b i b_i bi 先删除.
请输出 所有节点能否最后被删除.
S o l u t i o n 1 \mathcal{Solution_1} Solution1
步 骤 : \color{red}{步骤:} 步骤:
找 r o o t : \color{blue}{找\ root:} 找 root:
统 计 答 案 : \color{blue}{统计答案:} 统计答案:
以 r o o t root root 为根建树 :
对于一颗子树, 设该节点为 s s s,
分 两 种 情 况 讨 论 : 分两种情况讨论: 分两种情况讨论:
s \color{red}{s} s 有连出去的 有向边.
以 s \color{red}{s} s 为根节点的子树所有节点全部不能作为最后一个节点出去
理 由 : 不 明 \color{purple}理由: 不明 理由:不明
s \color{red}{s} s 没有连出去的 有向边 .
不操作
S o l u t i o n 2 \mathcal{Solution_2} Solution2
使用 树上差分, 以 d f n [ ] dfn[] dfn[] 为下标建立 差 分 数 组 差分数组 差分数组,
对于 a i , b i a_i, b_i ai,bi, 同样 a i a_i ai 向 b i b_i bi 连一条有向边,
先使用 拓 扑 排 序 拓扑排序 拓扑排序 判环, 若有环说明 无解, 否则 :
此时分为三种情况 :
对于 情 况 2 情况2 情况2 和 情 况 3 情况3 情况3, 直接将 d f n [ a ] , d f n [ a ] + s i z e [ a ] dfn[a], \ dfn[a]+size[a] dfn[a], dfn[a]+size[a] 进行差分操作,
对于 情 况 1 情况1 情况1, 记 全局数组 f l a g flag flag, 将 f l a g + + flag++ flag++,
b b b 跳到 a a a 的正下方后 !!
d f n [ b ] , d f n [ b ] + 1 dfn[b],\ dfn[b]+1 dfn[b], dfn[b]+1 进行 反差分操作.
最后根据 差 分 数 组 差分数组 差分数组 统计答案.
C o d e \mathcal{Code} Code
#include
#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;
}