zoukankan      html  css  js  c++  java
  • AGC018F. Two Trees

    题意

    给出两棵树,要求给两棵树上相同编号的点赋值,使得每个点的子树权值和的绝对值为1

    做法

    如果某个编号代表的点在一棵树中的儿子数为奇数而在另一棵树中的儿子数为偶数,那么无论这个位置填什么都不可能,否则可以构造只填0,1,-1的方案。具体做法是,分别考虑两棵树,如果一个点的儿子数为奇数,那么这个点填0;否则对于这个点所在的子树里的奇数儿子点两两配对,表示一个填1另一个填-1。把两棵树的配对情况一起建图,最后得到的必然是二分图,因为任何一个环上的边必然是交替来自两棵树内的配对。故而二染色填数即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5 + 100;
    
    int n, fa[N], fb[N], is_odd[2][N];
    
    struct Edge {
        int e, *h, *nx, *to, V, E;
        Edge(int V, int E):V(V), E(E) {
            e = 0;
            h = new int [V];
            nx = new int [E];
            to = new int [E];
            memset(h, -1, 4 * V);
        }
        ~Edge() {
            delete h;
            delete nx;
            delete to;
        }
        void clear() {
            e = 0;
            memset(h, -1, 4 * V);
        }
        void add(int u, int v) {
            to[e] = v, nx[e] = h[u], h[u] = e++;
            to[e] = u, nx[e] = h[v], h[v] = e++;
        }
    } *tr, *bi;
    
    int dfs(int u, int f) {
        vector<int> odd_son;
        for (int i = tr->h[u]; i != -1; i = tr->nx[i]) {
            int v = tr->to[i];
            if (v != f) {
                v = dfs(v, u);
                if (v != 0)
                    odd_son.push_back(v);
            }
        }
        if (!is_odd[0][u])
            odd_son.push_back(u);
        for (int i = 0; i < (int)odd_son.size() - 1; i += 2) {
            bi->add(odd_son[i], odd_son[i + 1]);
        }
        return odd_son.size() % 2 == 0 ? 0 : odd_son.back();
    }
    
    bool vis[N], col[N];
    
    void coloring(int u, int c) {
        vis[u] = true;
        col[u] = c;
        for (int i = bi->h[u]; i != -1; i = bi->nx[i]) {
            int v = bi->to[i];
            if (!vis[v])
                coloring(v, c ^ 1);
        }
    }
    
    int main() {
    #ifdef lol
        freopen("f.in", "r", stdin);
        freopen("f.out", "w", stdout);
    #endif
    
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &fa[i]);
            if (fa[i] != -1) {
                is_odd[0][fa[i]] ^= 1;
            }
        }
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &fb[i]);
            if (fb[i] != -1)
                is_odd[1][fb[i]] ^= 1;
        }
        for (int i = 1; i <= n; ++i) {
            if (is_odd[0][i] ^ is_odd[1][i]) {
                puts("IMPOSSIBLE");
                return 0;
            }
        }
        tr = new Edge(n + 1, (n + 1) * 2);
        bi = new Edge(n + 10, (n + 10) * 4);
        int rt;
        for (int i = 1; i <= n; ++i) {
            if (fa[i] == -1) {
                rt = i;
                continue;
            }
            tr->add(i, fa[i]);
        }
        dfs(rt, -1);
        tr->clear();
        for (int i = 1; i <= n; ++i) {
            if (fb[i] == -1) {
                rt = i;
                continue;
            }
            tr->add(i, fb[i]);
        }
        dfs(rt, -1);
        for (int i = 1; i <= n; ++i)
            if (!vis[i]) {
                coloring(i, 1);
            }
        puts("POSSIBLE");
        for (int i = 1; i <= n; ++i) {
            if (is_odd[0][i]) {
                printf("%d ", 0);
            } else {
                printf("%d ", col[i] ? 1 : -1);
            }
        }
        puts("");
    
        return 0;
    }
  • 相关阅读:
    (一)Kafka0.8.2官方文档中文版系列入门指南
    Hbase TTL(Time To Live)详解
    java源码学习详解Object类
    设计模式详细解读简单工厂方法模式
    (二)Kafka0.8.2官方文档中文版系列API
    Scala对象相等性判断
    scala中跳出循环的3种方法
    wpf 中借助 Grid 实现随着 Form 大小变化而按比例自动改变宽度或高度。
    static and cache
    约定编程之 Dictionary 的 String 类型的 Key
  • 原文地址:https://www.cnblogs.com/ichn/p/7580120.html
Copyright © 2011-2022 走看看