【学习笔记】[AGC018F] Two Trees

考虑如何将两棵树紧密的关联起来。单独看一个树的构造是没有意义的。如果一个点对应两棵树上度数的奇偶性不相等那么显然无解。其次对于一棵子树,度数为奇数的节点个数一定是 2 K + 1 2K+1 2K+1个,那么我们考虑能否将所有点两两配对,分为两种颜色的边,使得一个子树内蓝边和红边的数目之差恰好为一?

考虑构造欧拉回路,我们核心是要想到对于两个不同树中的两个相同节点连边,同时对于一颗子树上相邻的两个点连边。此时我们观察,这两棵树将点分成了两个集合,这两个集合之间相连的边就是我们想要的边,那么我们考虑这颗子树与外界相连的边包括连接两颗不同的树的边(我们想要的边)以及子树根节点到父亲的边。显然如果是指向子树内那么出子树的边恰好比进子树的边多一条,反之则恰好少一条。

那么为什么会想到欧拉回路呢?事实上,我们可以把它看成从源点出发的一条流量,这条流量最终会回到源点,那么根据流量平衡的思想,就有流出量=流入量,这样就保证了一棵子树内的 − 1 / 1 -1/1 1/1可以抵消。

复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define pb push_back #define inf 0x3f3f3f3f #define ull unsigned long long using namespace std; const int N=2e6+5; int n,res[N]; int rt1,rt2,d1[N],d2[N]; int head[N],nxt[N],to[N],w[N],vis[N],tot=1; stack<int>Q; void add(int x,int y,int z){ to[++tot]=y,w[tot]=z,nxt[tot]=head[x],head[x]=tot; to[++tot]=x,w[tot]=z,nxt[tot]=head[y],head[y]=tot; } void solve(){ Q.push(1); while(Q.size()){ int u=Q.top(); int k=head[u];while(k&&vis[k])k=nxt[k];head[u]=k; if(k){ if(w[k])res[min(u,to[k])]=(u<to[k])?1:-1; vis[k]=vis[k^1]=1;Q.push(to[k]); } else{ Q.pop(); } } } int main(){ cin>>n;for(int i=1;i<=n;i++){ int j;cin>>j;if(~j)d1[i]^=1,d1[j]^=1,add(i,j,0); else d1[i]^=1,rt1=i; }for(int i=1;i<=n;i++){ int j;cin>>j;if(~j)d2[i]^=1,d2[j]^=1,add(i+n,j+n,0); else d2[i]^=1,rt2=i; }add(rt1,rt2+n,0); for(int i=1;i<=n;i++)if(d1[i]!=d2[i]){ cout<<"IMPOSSIBLE";return 0; }for(int i=1;i<=n;i++)if(d1[i])add(i,i+n,1); cout<<"POSSIBLE"<<"\n"; solve(); for(int i=1;i<=n;i++)cout<<res[i]<<' '; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530071.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(11)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示