[AGC014E] Blue and Red Tree
Problem
给定一棵 \(n\) 个节点的树,一开始所有边都是蓝色的。每次选择一条所有边都是蓝色的路径,删掉其中一条边,然后在路径的两个端点之间连一条红边。求最后能不能得到目标形态(都是红边)的树。
Solution
膜一下 AGC 思维神题 orz!真的好巧妙!
这题倒着考虑。
假设你能得到目标形态的树,那么最后一条蓝边和最后一条红遍必然相同。
那么此时这两个点已经互不相干了,我们不妨把它缩成一个点,也就是说他俩的连边都看成连到一个点上。
这是一个类似归纳法的过程!
也就是说,我们现在由原来 \(n\) 个点变成了 \(n-1\) 个点的树,那么现在也一定存在着一条重合的红蓝边!
如此合并 \(n - 1\) 次,就做完了!
只能说听起来就非常正确,感性理解吧qwq。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(f)x=-x;
}
template <typename T,typename ...Args>
inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);}
const int N = 1e5 + 5;
int n,l,r,cnt;
multiset<int>s[N];
map<pair<int,int>,int>mp;
queue<pair<int,int>>q;
inline void add(int u,int v){
if(u > v)swap(u,v);
if(u == v)return;
if(++mp[{u,v}] == 2)q.push({u,v});
s[u].insert(v),s[v].insert(u);
}
signed main(){
read(n);
rep(i,1,(n-1)*2){
int u,v;
read(u,v);
add(u,v);
//printf("u=%d v=%d\n",u,v);
}
while(cnt < n - 1){
if(q.empty())return puts("NO"),0;
auto it = q.front();
q.pop();
if(!mp[it])continue;
int u = it.first,v = it.second;
if(s[u].size() < s[v].size())swap(u,v);
for(int x : s[v]){
mp[{min(x,v),max(x,v)}] = 0;
s[x].erase(s[x].find(v));
add(x,u);
}
s[v].clear();cnt++;
}
puts("YES");
}