[AGC014E] Blue and Red Tree

Problem

link

给定一棵 \(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");
}   
posted @ 2022-09-14 21:01  Xu_brezza  阅读(22)  评论(0编辑  收藏  举报