AGC 018 F

F - Two Trees

链接

题意:

  给定两棵都是N个节点的有根树,节点均从1~N标号。给每个标号定一个权值(类似一号点的权值是x,那么两棵树中1号点的权值都是x),使在两棵树满足以任意节点为根的子树的权值和为1或-1。输出任意一种解或判断无解,N<=100000。

分析:

  欧拉回路。

  首先每棵子树的权值和都-1或者1,,如果知道了每个点有多少个子节点,那么就可以知道他的奇偶性(奇数个儿子=>权值为偶数,偶数个儿子=>权值为奇数)。现在可以判断无解了:如果同一个节点在两棵树内的奇偶性不同。

  然后建立一个0点,将两棵树连起来;然后一个标号的点在两棵树上是奇点,那么有第一棵树的这个点向第二棵树的这个点连一条边(x->x+n)。然后跑欧拉回路,对于从第一棵树到第二颗树的点,权值为1,否则为-1,偶点为0。

  具体的解释证明,画一下,挺对的。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 500005;
struct Edge{
    int fr, to, nxt; 
}e[N << 1];
int head[N], f1[N], f2[N], c1[N], c2[N], sk[N << 1], ans[N], top = 0, En = 1;
bool vis[N << 1];

inline void add_edge(int u,int v) {
//    cout << u << " " << v << "
";
    ++En; e[En].fr = u, e[En].to = v, e[En].nxt = head[u]; head[u] = En;
    ++En; e[En].fr = v, e[En].to = u, e[En].nxt = head[v]; head[v] = En;
}
void dfs(int u) {
    while (1) {
        int k = head[u]; 
        if (!k) break;
        head[u] = e[k].nxt;
        if (!vis[k]) {
            vis[k] = vis[k ^ 1] = 1;
            dfs(e[k].to);
            sk[++top] = k;
        }
    }
}
int main() {
    freopen("1.txt", "r", stdin);
    int n = read();
    for (int i = 1; i <= n; ++i) {
        int x = read();
        if (x == -1) x = 0;
        f1[i] = x, c1[x] ++;
        add_edge(x, i);
    }
    for (int i = 1; i <= n; ++i) {
        int x = read();
        if (x == -1) x = 0;
        f2[i] = x, c2[x] ++;
        if (x == 0) add_edge(x, i + n);
        else add_edge(x + n, i + n);
    }
    for (int i = 1; i <= n; ++i) {
        if (c1[i] % 2 != c2[i] % 2) { puts("IMPOSSIBLE"); return 0; }
        if ((c1[i] & 1) && (c2[i] & 1)) ans[i] = 0;
        else add_edge(i, i + n);
    }
    puts("POSSIBLE");
    dfs(0);
    for (int i = top; i >= 1; --i) {
        int k = sk[i];
        if (e[k].fr + n == e[k].to) ans[e[k].fr] = 1;
        if (e[k].fr - n == e[k].to) ans[e[k].fr - n] = -1;
    }
    for (int i = 1; i <= n; ++i) {
        printf("%d ", ans[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10279477.html