CF724G. Xor-matic Number of the Graph

题意

http://codeforces.com/contest/724/problem/G
定义三元组\((u,v,s)(u<v)\):\(u\)到\(v\)的路径的\(xor\)和为\(s\)(可以不是简单路径),\((u,v,s)\)不同当且仅当\(u,v,s\)的其中一个参数不同。
求所有不同三元组的\(s\)值之和。
\(n \in [1,10^5],m\in [0, 2\cdot 10^5], w\in [0,10^{18}]\)

题解

显然在同个联通块中,当前联通块中的所有环都可以被取到。而且每一条路径一定是一条简单路径与若干个环的\(xor\)和组成。
环的部分可以利用线性基来统计可以组成的不同的\(xor\)值个数。
\(dfs\)出搜索树,做树上前缀和,那么一条简单路径的\(xor\)和就是\(s[u] \oplus s[v]\),并顺便处理出所有环的\(xor\)和扔进线性基里。
因为\(xor\)对各位互不影响所以考虑按位处理。
对于第\(k\)位,将\(s\)划分为第\(k\)位为\(0\)和为\(1\)的,数量记为\(c_0\)和\(c_1\)
可以划分为\(3\)种情况:

  • \(0 \oplus 0\),共\(\frac{c_0\times (c_0-1)}{2}\)种。
  • \(1 \oplus 1\),共\(\frac{c_1\times (c_1-1)}{2}\)种。
  • \(1 \oplus 0\),共\(c_0 \times c_1\)种。

同时线性基中也有第\(k\)位为\(0\)和第\(k\)位为\(1\)的两种情况。
几种情况分别组合一下就好。
设线性基为\(b\)。则有

  • \(b[k]=0\)时,对于情况三,贡献的不同\(xor\)和为\(2^{|b|}\)种。对于情况一和情况二,贡献为\(0\)。
  • \(b[k]=1\)时,对于情况三,贡献的不同\(xor\)和为\(2^{|b|-1}\)种。对于情况一和情况二,贡献为\(2^{|b|-1}\)种。

复杂度为\(O(n \log^2 \max(w_i))\)

#include <bits/stdc++.h>
using namespace std;

namespace io {
char buf[1<<21], *p1 = buf, *p2 = buf, buf1[1<<21];
inline char gc() {
    if(p1 != p2) return *p1++;
    p1 = buf;
    p2 = p1 + fread(buf, 1, 1 << 21, stdin);
    return p1 == p2 ? EOF : *p1++;
}
#define G gc

#ifndef ONLINE_JUDGE
#undef G
#define G getchar
#endif

template<class I>
inline void read(I &x) {
    x = 0; I f = 1; char c = G();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
    while(c >= '0' && c <= '9') {x = x * 10LL + c - '0'; c = G(); }
    x *= f;
}

template<class I>
inline void write(I x) {
    if(x == 0) {putchar('0'); return;}
    I tmp = x > 0 ? x : -x;
    if(x < 0) putchar('-');
    int cnt = 0;
    while(tmp > 0) {
        buf1[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while(cnt > 0) putchar(buf1[--cnt]);
}

#define in(x) read(x)
#define outn(x) write(x), putchar('\n')
#define out(x) write(x), putchar(' ')

} using namespace io;

#define ll long long
const int N = 100010;
const ll mod = 1e9 + 7;

int cnt = 1, head[N];
struct edge {int to, nxt; ll v;} e[N<<2];
int n, m, tot;
ll s[N], b[N], ans, pw[N];
bool vis[N];

struct lb {

    ll p[64];
    vector<ll> a;

    void clear() {
        a.clear();
        memset(p, 0, sizeof(p));
    }

    void insert(ll x) {
        for(ll i = 63; i >= 0; --i)
            if((x >> i) & 1LL) {
                if(p[i]) x ^= p[i];
                else {
                    p[i] = x;
                    return;
                }
            }
    }

    void init() {
        for(int i = 0; i <= 63; ++i) {
            if(p[i])
            for(int j = i - 1; j >= 0; --j) {
                if((p[j] >> i) & 1) p[i] ^= p[j];
            }
        }
        for(int i = 0; i <= 63; ++i)
            if(p[i]) a.push_back(p[i]);
    }

    ll solve(ll k, ll c, ll v) {
        bool flag = 0; v %= mod;
        for(int i = 0; i < (int)a.size(); ++i) {
            if((a[i] >> k) & 1) flag = 1;
        }
        if(c) {
            if(flag) return 1LL * pw[(int)a.size() - 1] * v % mod;
            return 1LL * pw[(int)a.size()] * v % mod;
        } else {
            if(flag) return 1LL * pw[(int)a.size() - 1] * v % mod;
            return 0;
        }
    }

}B;

void ins(int u, int v, ll w) {
    e[++cnt] = {v, head[u], w};
    head[u] = cnt;
}

void dfs(int u, int in_edge) {
    vis[u] = 1;
    b[++tot] = s[u];
    for(int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(in_edge == (i ^ 1)) continue;
        if(vis[v]) {
            B.insert(s[u] ^ s[v] ^ e[i].v);
            continue;
        }
        s[v] = s[u] ^ e[i].v;
        dfs(v, i);
    }
}

ll power(ll x, ll y) { ll ans = 1;
    while(y) {
        if(y & 1) ans = ans * x % mod;
        x = x * x % mod; y >>= 1;
    } return ans;
}
ll inv2 = power(2, mod - 2);

void solve() {
    ll c[2] = {0, 0};
    for(ll k = 0; k < 64; ++k) {
        c[0] = c[1] = 0;
        for(int i = 1; i <= tot; ++i) c[(b[i] >> k) & 1LL]++;
        if(c[0]) (ans += B.solve(k, 0, (1LL << k) % mod * c[0] % mod * (c[0] - 1LL) % mod) * inv2 % mod) %= mod;
        if(c[1]) (ans += B.solve(k, 0, (1LL << k) % mod * c[1] % mod * (c[1] - 1LL) % mod) * inv2 % mod) %= mod;
        (ans += B.solve(k, 1, (1LL << k) % mod * c[0] % mod * c[1] % mod)) %= mod;
    }
}

int main() {
    read(n); read(m);
    for(int u, v, i = 1; i <= m; ++i) {
        ll w;
        read(u); read(v); read(w);
        ins(u, v, w), ins(v, u, w);
    }
    pw[0] = 1;
    for(int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * 2LL % mod;
    for(int i = 1; i <= n; ++i) {
        if(!vis[i]) {
            B.clear(); tot = 0;
            dfs(i, 0);
            B.init();
            solve();
        }
    }
    outn((ans%mod+mod)%mod);
}
/*
10 20
1 2 0
4 3 3
6 8 7
10 1 4
3 8 0
10 7 0
9 7 9
7 1 10
6 7 2
8 5 10
4 5 7
10 4 2
6 9 10
6 10 10
10 5 5
4 1 4
9 8 0
2 3 7
4 7 4
3 1 7
*/

原文地址:https://www.cnblogs.com/henry-1202/p/11429038.html

时间: 2024-11-09 03:04:45

CF724G. Xor-matic Number of the Graph的相关文章

CF724G 【Xor-matic Number of the Graph】

题目就不翻译了吧,应该写的很清楚了... 首先 $,$ 不懂线性基的可以戳这里.知道了线性基$,$ 但是从来没有写过线性基和图论相结合的$,$ 可以戳这里. 好$,$ 点完了这些前置技能之后,我们就可以来愉快的切题啦! 正片$:$ 类比$[WC$ $2011]$ 最大$xor$和路径$,$ 我们肯定要找环$,$ 找完环后再用环去构造线性基$,$ 因为还是那句话嘛$:$ 任何一条复杂路径$,$ 都能有起始两点的一条简单路径再加上若干个环组成. 那么接下来的问题就是$:$如何求出亦或值的和? $en

Codeforces 724 G Xor-matic Number of the Graph 线性基+DFS

G. Xor-matic Number of the Graph http://codeforces.com/problemset/problem/724/G 题意:给你一张无向图.定义一个无序三元组(u,v,s)表示u到v的(不一定为简单路径)路径上xor值为s.求出这张无向图所有不重复三元组的s之和.1≤n≤10^5,1≤m≤2*10^5. 想法: 如果做过[Wc2011 xor]这道题目(题解),那么问题变得简单起来了. ①假设我们钦定一个(u,v),设任意一条u->v的路径xor值为X,

724G - Xor-matic Number of the Graph(线性基)

724G - Xor-matic Number of the Graph 题意: 待补~~ 参考http://www.cnblogs.com/ljh2000-jump/p/6443189.html

Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) G - Xor-matic Number of the Graph 线性基好题

G - Xor-matic Number of the Graph 上一道题的加强版本,对于每个联通块需要按位算贡献. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define PLI pair<LL, int> #define ull unsigned lo

CodeForces - 724G Xor-matic Number of the Graph

Discription You are given an undirected graph, constisting of n vertices and m edges. Each edge of the graph has some non-negative integer written on it. Let's call a triple (u,?v,?s) interesting, if 1?≤?u?<?v?≤?n and there is a path (possibly non-si

CF.724G.Xor-matic Number of the Graph(线性基)

题目链接 \(Description\) 给定一张带边权无向图.若存在u->v的一条路径使得经过边的边权异或和为s(边权计算多次),则称(u,v,s)为interesting triple. 求图中所有interesting triple中s的和. \(Solution\) 同[WC2011]Xor,任意两点路径的Xor和是它们间(任意一条)简单路径的和Xor一些环的和.so可以先处理出环上的和,构造线性基.两点间的一条简单路径可以直接求个到根节点的dis[]. 有了各点的dis,然后考虑用组合

hdu 4034 Graph(深化最短路floyd)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4034 Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2188    Accepted Submission(s): 1101 Problem Description Everyone knows how to calculat

Graph(Floyd)

http://acm.hdu.edu.cn/showproblem.php?pid=4034 Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 2058    Accepted Submission(s): 1030 Problem Description Everyone knows how to calculate the

hdu4034 Graph(floyd)

题目:  给出一个图的最短路,求原图最少几条边 Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 1695    Accepted Submission(s): 848 Problem Description Everyone knows how to calculate the shortest path in a direc