agc018F Two Tree
Solution
-
这是一道神奇的结论题。
-
首先你可以手玩一下,可以发现如果根据一个节点儿子的个数可以确定当前权值的奇偶性,如果在两棵树中奇偶性不同则无解。
-
进一步的可以感受到如果满足上面的条件只需要 − 1 , 0 , 1 -1,0,1 −1,0,1就可以构造出来。
-
考虑关键的在于未确定的 − 1 , 1 -1,1 −1,1,我们需要一个东西来平衡子树内的权值。
-
对于这种看起来是线性的构造问题,一般需要用图论、连边来解决。
-
在我们本就不多的图论知识中,可以用欧拉回路或二分图染色来解决它。
欧拉回路
- 不妨考虑关键的奇点 ( − 1 / 1 ) (-1/1) (−1/1),我们用欧拉回路走出来的边的方向来确定是 − 1 -1 −1还是 1 1 1。
- 考虑对于奇数点将两棵树点相连,再加一个虚点,向两棵树的根连边,剩下的都是树上的边。
- 直接在这个图上跑欧拉回路,对于横插边左到右为 1 1 1,否则为 − 1 -1 −1。
- 可以发现对于一个点的子树内,如果不考虑父亲边,一定是进一个出一个, + 1 , − 1 +1,-1 +1,−1相互抵消,那么考虑上父亲边贡献就是 1 / − 1 1/-1 1/−1了。
二分图染色
- 考虑对于一个子树内,一定有 2 K + 1 2K+1 2K+1个奇点(为 1 / − 1 1/-1 1/−1),考虑它们两两相消,最后留下一个就是对当前子树的根节点的贡献。
- 不妨对于两棵树都以某种方法匹配,使得对于每个子树都有 K K K对匹配。
- 将两棵树匹配的边分别设为红边和蓝边,钦定连了边的两个点权值不同,再将两棵树的相同标号点合并,显然这样没有奇环,那么就构造完了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 200005
#define maxm 1000005
using namespace std;
int n,i,j,k,du[maxn],v[maxn];
int em,e[maxm],nx[maxm],ls[maxn],bz[maxm];
void insert(int x,int y){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; du[x]++;
em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; du[y]++;
}
int d[maxm];
void dfs(int x){
while (ls[x]){
int i=ls[x],y=e[i];
if (!bz[i]){
bz[i]=bz[i^1]=1,ls[x]=nx[ls[x]];
dfs(y);
} else ls[x]=nx[ls[x]];
}
d[++d[0]]=x;
}
int main(){
freopen("ceshi.in","r",stdin);
scanf("%d",&n),em=1;
for(i=1;i<=n;i++) scanf("%d",&k),insert(i,(k<0)?0:k);
for(i=1;i<=n;i++) scanf("%d",&k),insert(i+n,(k<0)?0:(k+n));
for(i=1;i<=n;i++) if ((du[i]&1)!=(du[i+n]&1)) printf("IMPOSSIBLE"),exit(0);
for(i=1;i<=n;i++) if (du[i]&1) insert(i,i+n);
dfs(0);
for(i=1;i<d[0];i++) if (d[i]&&d[i+1]&&abs(d[i]-d[i+1])==n)
v[min(d[i],d[i+1])]=(d[i]<d[i+1])?-1:1;
printf("POSSIBLE\n");
for(i=1;i<=n;i++) printf("%d ",v[i]);
}