Two Trees
题解
首先,我们要说明一点,如果该题有解,那么我们用
{
−
1
,
0
,
1
}
\{-1,0,1\}
{−1,0,1}一定可以构造出一组解。
其实很容易理解的
对于一个点,它的权值有它儿子的个数决定,设子树 i i i的权值和为 v a l i val_{i} vali。
容易发现 v a l u = ( 1 / − 1 ) − ∑ v ∈ S o n u v a l v val_{u}=(1/-1)-\sum_{v\in Son_{u}}val_{v} valu=(1/−1)−∑v∈Sonuvalv。
对于任意一个有合法子树点 v v v,如果我们将它子树中所有数的权值全部反转,它依旧是合法的,只不过 v a l v val_{v} valv会变为 − v a l v -val_{v} −valv。
于是我们一定存在一种方法使得有奇数个儿子的点的儿子的 v a l val val和为 0 0 0,有偶数个儿子的点的儿子的 v a l val val和为 1 / − 1 1/-1 1/−1。这只需要通过调配儿子的 v a l val val在 1 1 1与 − 1 -1 −1间转化就可以得到。
于是,点 u u u的权值可以只用 { − 1 , 0 , 1 } \{-1,0,1\} {−1,0,1}就可以构造出一种合法解。
于是,我们只需要用 { − 1 , 0 , 1 } \{-1,0,1\} {−1,0,1}去构造即可。
很容易发现,对于有偶数个儿子的节点,它的权值一定是
1
1
1或
−
1
-1
−1,称其为偶点;
对于有奇数个儿子的节点,它的权值一定为0,称其为奇点。
由于任意节点的子树的总权值和只能为
1
1
1或
−
1
-1
−1,所以我们需要将所有的偶点一一匹配,使得任意节点的子树中只有一个偶点没有被匹配。
对于匹配了的偶点,我们可以再它们之间连边。
由于每棵树只会对一个偶点产生
1
1
1的度数贡献,我们最后得到的一定是若干个偶环(由于一个节点在一棵树中只能匹配一个节点,不可能得到奇环)。
我们可以将这个偶环根据遍历到的顺序当作二分图,一边的节点赋值为
1
1
1,另一边赋值为
−
1
-1
−1。
只有当一个节点在两棵树上奇偶性不同时才会无解,否则一定有解。
时间复杂度
O
(
n
)
O\left(n\right)
O(n)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,Head[MAXN],Tot,val[MAXN];bool vis[MAXN];
struct edge{int to,nxt;}E[MAXN<<1];
void addedge(const int u,const int v){E[++Tot]=(edge){v,Head[u]};Head[u]=Tot;}
struct Tree{
edge e[MAXN<<1];
int siz[MAXN],head[MAXN],tot,p[MAXN],sta[MAXN],stak;
void addEdge(const int u,const int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void dfs(const int x,const int fa){
siz[x]=1;
for(reg int i=head[x];i;i=e[i].nxt){
const int v=e[i].to;if(v==fa)continue;
dfs(v,x);siz[x]++;
}
stak=0;for(reg int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa)sta[++stak]=p[e[i].to];
for(reg int i=2;i<=stak;i+=2){
const int u=sta[i-1],v=sta[i];
addedge(u,v);addedge(v,u);
}
p[x]=(siz[x]&1)?x:p[x]=sta[stak];
}
void build(){
int root;
for(reg int i=1,x;i<=n;++i){
read(x);if(x<0){root=i;continue;}
addEdge(i,x);addEdge(x,i);
}
dfs(root,0);
}
}T1,T2;
void dfs(const int x,const int w){
val[x]=w;vis[x]=1;
for(reg int i=Head[x];i;i=E[i].nxt)
if(!vis[E[i].to])dfs(E[i].to,-w);
}
signed main(){
read(n);T1.build();T2.build();
for(reg int i=1;i<=n;++i)if((T1.siz[i]&1)!=(T2.siz[i]&1)){puts("IMPOSSIBLE");return 0;}
for(reg int i=1;i<=n;++i)if(!vis[i]&&(T1.siz[i]&1))dfs(i,1);
puts("POSSIBLE");for(reg int i=1;i<=n;++i)printf("%d ",val[i]);puts("");
return 0;
}