【AGC018F】Two Trees 构造 黑白染色

来源:互联网 发布:淘宝买多少单有一颗心 编辑:程序博客网 时间:2024/05/16 11:32

题目描述

  有两棵有根树,顶点的编号都是1~n

  你要给每个点一个权值ai,使得对于两棵树的所有顶点x,满足|x的子树的权值和|=1

  n100000

题解

  我们很容易得到只考虑一棵树时每个点的权值的奇偶性。如果只考虑A树时的奇偶性与只考虑B树时的奇偶性不同,就无解。

  现在我们构造一个ai{1,0,1}的方案。

  如果一个点的儿子个数是奇数,那么ai=0,否则ai0

  现在只考虑一棵子树。

  对于每一棵子树,一定有2k+1个权值是奇数的点。

  证明:因为整棵子树的权值和是奇数,所以有奇数个权值是奇数的点。

  那么可以匹配出k对点和剩下一个点。对于一对点(x,y),令ax=ay。所以整棵子树的权值和就是±1。我们在x,y之间连一条边。对于每个点

  这样得到的图每个点的度数1

  然后把两棵树得到的边合在一起,得到的图就是一个二分图。

  为什么?因为如果有奇环就一定会有相邻两条边来自同一棵树,但这是不可能的。所以就没有奇环。

  对于这个图黑白染色,黑色的点选1,白色的点选1

  时间复杂度:O(n)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>#include<cmath>#include<functional>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;typedef pair<ll,ll> pll;void sort(int &a,int &b){    if(a>b)        swap(a,b);}void open(const char *s){#ifndef ONLINE_JUDGE    char str[100];    sprintf(str,"%s.in",s);    freopen(str,"r",stdin);    sprintf(str,"%s.out",s);    freopen(str,"w",stdout);#endif}int rd(){    int s=0,c;    while((c=getchar())<'0'||c>'9');    do    {        s=s*10+c-'0';    }    while((c=getchar())>='0'&&c<='9');    return s;}int upmin(int &a,int b){    if(b<a)    {        a=b;        return 1;    }    return 0;}int upmax(int &a,int b){    if(b>a)    {        a=b;        return 1;    }    return 0;}struct graph{    int v[200010];    int t[200010];    int h[100010];    int n;    graph()    {        n=0;    }    void add(int x,int y)    {        v[++n]=y;        t[n]=h[x];        h[x]=n;    }};graph g1,g2,g;int fa[100010];int fb[100010];int a1[100010];int a2[100010];int st[100010];int top;int b[100010];int c[100010];void dfs1(int x){    int i;    for(i=g1.h[x];i;i=g1.t[i])        dfs1(g1.v[i]);    if(a1[x])        st[++top]=x;    while(top>=2)    {        g.add(st[top],st[top-1]);        g.add(st[top-1],st[top]);        top-=2;    }}void dfs2(int x){    int i;    for(i=g2.h[x];i;i=g2.t[i])        dfs2(g2.v[i]);    if(a2[x])        st[++top]=x;    while(top>=2)    {        g.add(st[top],st[top-1]);        g.add(st[top-1],st[top]);        top-=2;    }}void dfs(int x,int v){    c[x]=v;    b[x]=1;    int i;    for(i=g.h[x];i;i=g.t[i])        if(!b[g.v[i]])            dfs(g.v[i],-v);}int main(){//  open("agc018f");    int n;    scanf("%d",&n);    int i;    int rt1,rt2;    for(i=1;i<=n;i++)        a1[i]=a2[i]=1;    for(i=1;i<=n;i++)    {        scanf("%d",&fa[i]);        if(fa[i]==-1)            rt1=i;        else        {            g1.add(fa[i],i);            a1[fa[i]]^=1;        }    }    for(i=1;i<=n;i++)    {        scanf("%d",&fb[i]);        if(fb[i]==-1)            rt2=i;        else        {            g2.add(fb[i],i);            a2[fb[i]]^=1;        }    }    for(i=1;i<=n;i++)        if(a1[i]!=a2[i])        {            printf("IMPOSSIBLE\n");            return 0;        }    printf("POSSIBLE\n");    top=0;    dfs1(rt1);    top=0;    dfs2(rt2);    for(i=1;i<=n;i++)        if(!b[i])            dfs(i,1);    for(i=1;i<=n;i++)        if(!a1[i])            printf("0 ");        else            printf("%d ",c[i]);    return 0;}