AT2377-[AGC014E]Blue and Red Tree【启发式合并】

1|0正题

题目链接:https://www.luogu.com.cn/problem/AT2377


1|1题目大意

有两棵树T1,T2T1树上的边开始时都是蓝色的,我们每次选择一条蓝色边路径(x,y),然后删掉路径上一条边,连接一条xy的红色边。

要求最后所有都是红色边的情况下能不能变成T2

1n105


1|2解题思路

考虑反过来,所以开始时视T1上没有边,我们从T2开始考虑,对于每一条(x,y)它合法的时机当且仅当T1x,y的路径上只剩下一条边没有补上。

所以这个时候我们直接选择这条路径补上这条边一定是对的,因为如果被其他的补上了就不合法,而它也只会补上这条边。

此时我们的方案就唯一了,实现的时候我们可以每次找到一条两棵树上都有的边(x,y),然后将节点x和节点y合并,我们用set来记录每个点连出去的边,合并的时候就启发式合并就好了。

时间复杂度:O(nlog2n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<map> #define mp(x,y) make_pair(x,y) using namespace std; const int N=1e5+10; int n;multiset<int> s[N]; queue<pair<int,int> > q; map<int,int> mp[N]; void addl(int x,int y){ if(x==y)return; if(x>y)swap(x,y);mp[x][y]++; s[x].insert(y);s[y].insert(x); if(mp[x][y]==2)q.push(mp(x,y)); return; } int main() { scanf("%d",&n); for(int i=1,x,y;i<2*n-1;i++) scanf("%d%d",&x,&y),addl(x,y); while(!q.empty()){ int x=q.front().first,y=q.front().second; q.pop();if(!mp[x][y])continue; if(s[x].size()<s[y].size())swap(x,y); while(!s[y].empty()){ int z=*s[y].begin(); mp[min(z,y)][max(z,y)]=0; s[z].erase(s[z].find(y)); s[y].erase(s[y].begin()); addl(x,z); } n--; } if(n==1)puts("YES"); else puts("NO"); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16546374.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示