zoukankan      html  css  js  c++  java
  • [构造] Codeforces 1615D X(or)mas Tree

    题目大意

    给定一棵 \(n(1\leq n\leq 2\times 10^5)\) 个点的树,树上有的边有边权,有的边没有。给出 \(m(1\leq m\leq 2\times 10^5)\) 个限制,每次限制了 \(u\)\(v\) 路径上的边权的异或和的二进制位上 \(1\) 的个数是奇数还是偶数。现在要求给没有边权的边赋予边权,使得满足所有限制。

    题解

    \(f(x)\) 表示 \(x\) 的二进制位上 \(1\) 的个数的奇偶性,即若 \(x\) 的二进制位上有偶数个 \(1\),则 \(f(x)=0\);若 \(x\) 的二进制位上有奇数个 \(1\),则 \(f(x)=1\)。假设 \(u\)\(v\) 的路径上有一系列边权 \(\{w_1,w_2,\cdots,w_k\}\),则每次限制了 \(f(w_1\bigoplus w_2 \bigoplus \cdots \bigoplus w_k)=0\)\(f(w_1\bigoplus w_2 \bigoplus \cdots \bigoplus w_k)=1\)。显然有 \(f(w_1\bigoplus w_2 \bigoplus \cdots \bigoplus w_k)=f(w_1)\bigoplus f(w_2)\bigoplus \cdots \bigoplus f(w_k)\),所以我们可以把原先的边权 \(w\) 看成 \(f(w)\),需要赋予的边权要么是 \(0\) 要么是 \(1\) 即可。

    \(s[u]\) 表示 \(u\) 到根的路径上 \(f(w)\) 的异或和,则每次限制了 \(s[u]\bigoplus s[v]=0\)\(s[u]\bigoplus s[v]=1\),对于原先已有边权的边 \((u,v,w)\),则相当于限制了 \(s[u] \bigoplus s[v]=f(w)\)。于是我们可以对所有的这些限制建一张新图,当限制了 \(s[u]\bigoplus s[v]\) 的取值时,在新图的 \(u,v\) 之间直接连一条边,边权是 \(s[u]\bigoplus s[v]\),此时 \(u,v\) 两点的点权 \(s[u],s[v]\) 异或起来应该等于边权。在新图中可以划分出若干连通块,每个连通块中只需要在一开始令某个点 \(u\) 的点权 \(s[u]\) 等于 \(0\)\(1\) 时,这个连通块内所有的点权就已经确定了,都可以通过异或边权转移得到。若无论点权赋成 \(0\)\(1\) 都存在矛盾,则无解。于是我们计算出了一组合法的 \(s[u]\)。最终对于一开始没有边权的边 \((fa,u)\)\(fa\)\(u\) 的父亲,则 \((fa,u)\) 这条边的边权就可以赋值为 \(s[u]\bigoplus s[fa]\)

    时间复杂度 \(O(n+m)\)

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    template<typename elemType>
    inline void Read(elemType& T) {
        elemType X = 0, w = 0; char ch = 0;
        while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        T = (w ? -X : X);
    }
    
    struct Graph {
        struct edge { int Next, to, w; };
        edge G[800010];
        int head[200010];
        int cnt;
    
        Graph() :cnt(2) {}
        void clear(int n) {
            cnt = 2;fill(head, head + n + 2, 0);
        }
        void add_edge(int u, int v, int w) {
            G[cnt].w = w;
            G[cnt].to = v;
            G[cnt].Next = head[u];
            head[u] = cnt++;
        }
    };
    Graph G, G2;
    bool vis[200010];
    int s[200010];
    int T, n, m;
    
    inline int f(int x) { return __builtin_parity(x); }
    
    void Output(int u, int fa) {
        for (int i = G.head[u];i;i = G.G[i].Next) {
            int v = G.G[i].to;
            if (v == fa) continue;
            if (G.G[i].w == -1) printf("%d %d %d\n", u, v, s[u] ^ s[v]);
            else printf("%d %d %d\n", u, v, G.G[i].w);
            Output(v, u);
        }
    }
    
    vector<int> buf;
    
    bool DFS(int u) {
        vis[u] = true;
        buf.push_back(u);
        for (int i = G2.head[u];i;i = G2.G[i].Next) {
            int v = G2.G[i].to, w = G2.G[i].w;
            if (vis[v]) {
                if (s[v] ^ s[u] != w) return false;
                continue;
            }
            s[v] = w ^ s[u];
            if (!DFS(v)) return false;
        }
        return true;
    }
    
    int main() {
        Read(T);
        while (T--) {
            Read(n);Read(m);
            G.clear(n);
            G2.clear(n);
            for (int i = 1;i <= n - 1;++i) {
                int u, v, w;
                Read(u); Read(v); Read(w);
                G.add_edge(u, v, w);
                G.add_edge(v, u, w);
                if (w != -1) {
                    w = f(w);
                    G2.add_edge(u, v, w);
                    G2.add_edge(v, u, w);
                }
            }
            fill(vis + 1, vis + n + 1, false);
            bool flag = true;
            for (int i = 1;i <= m;++i) {
                int u, v, w;
                Read(u); Read(v); Read(w);
                if (u == v) {
                    if (w) flag = false;
                    continue;
                }
                G2.add_edge(u, v, w);
                G2.add_edge(v, u, w);
            }
            if (!flag) { printf("NO\n"); continue; }
            for (int u = 1;u <= n;++u) {
                if (vis[u]) continue;
                s[u] = 0; buf.clear();
                if (!DFS(u)) {
                    for (auto x : buf) vis[x] = false;
                    buf.clear(); s[u] = 1;
                    if (!DFS(u)) { flag = false; break; }
                }
            }
            if (!flag) {
                printf("NO\n");
                continue;
            }
            printf("YES\n");
            Output(1, 0);
        }
        return 0;
    };
    
    
  • 相关阅读:
    北京Uber优步司机奖励政策(3月3日)
    ubuntu安装phpstorm
    ubuntu安装typora
    PHP定时任务Crontab结合CLI模式详解
    mysql创建用户,并授予权限
    ubuntu下使用crontab定时器
    Ubuntu 查看当前目录使用的总空间大小
    ubuntu安装ruby,安装sass,安装compass
    open_basedir restriction in effect,解决php引入文件权限问题 lnmp
    canvas 画线
  • 原文地址:https://www.cnblogs.com/AEMShana/p/15731793.html
Copyright © 2011-2022 走看看