题意:
一个无向图,边上有边权。定义一条路的价值为这条路径上边权的异或和,两个点之间的价值为它们所有路径不同价值的和,整个图的价值为所有点对价值的和。
求整个图的价值。
做法:
首先考虑对于树的做法:
记点i到根路径的异或和为f[i],则点对u,v路径的异或和就是f[u]^f[v].
n^2做法就直接枚举任意两点。
考虑“异或”的套路:由于每一位互不干扰,我们可以按位处理。
对于第x位,如果f[1..n]中有a个1,b个0,对答案的贡献就是a×b×2^x.
发现对于一个图的一个连通分量,其实就是它的一个生成树上有一些非树边,构成了环。
假如跑出任意一个生成树,任意两点的价值就是它树上的路径的异或和异或上一些简单环的异或和。
树上的问题就解决了,还要处理环的问题。
我们可以把所有环的异或和放到一个线性基里去。
然后类似的,按位处理出每一位对答案的贡献。
对于第x位,如果f[1..n]中有a个1,b个0,则他们有a×b种方案得到1.
记线性基中有m个元素。
如果这一位线性基中的元素全为0,则随便怎么选都可以,共2^m种方案。
如果这一位线性基中有某个元素为1,则无论其它元素怎么选,这个元素都存在唯一的选或不选的方案,共2^(m-1)种方案。
当然,他们还有C(a,2)+C(b,2)种方案得到0.
如果这一位线性基中的元素全为0,则不可能得到1,方案数为0。
如果这一位线性基中有某个元素为1,则无论其它元素怎么选,这个元素都存在唯一的选或不选的方案,共2^(m-1)种方案(同上)。
然后用乘法原理和加法原理就可以计算出答案(注意别忘记乘这一位的值2^x)
记得开long long.
代码:
/*************************************************************
Problem: codeforces 724G - Xor-matic Number of the Graph
User: RainbowGirl
Language: C++
Result: Accepted
Time: 233 ms
Memory: 13100 KB
Submit_Time: 2018-01-15 10:08:58
*************************************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long LL;
inline LL read()
{
char ch = getchar(); LL x = 0; int op = 1;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
for(; isdigit(ch); ch = getchar()) x = x*10 + ch-'0';
return x*op;
}
inline void write(LL a) { if(a < 0) putchar('-'), a = -a; if(a >= 10) write(a/10); putchar(a%10+'0'); }
const int N = 200010;
const LL mod = 1e9 + 7;
int n, m, cnt;
int head[N], vis[N];
LL f[N], g[100][2], a[100], p[200], used, ans, tot;
struct edge{
int to, nxt; LL v;
edge() {}
edge(int x, int y, LL z) { to = x, nxt = y, v = z; }
}e[N<<1];
inline void addedge(int x, int y, LL z) { e[++ cnt] = edge(y, head[x], z); head[x] = cnt; }
inline void insert(LL x)
{
used |= x;
for(int i = 60; i >= 0; i --)
if(x>>i&1) {
if(a[i]) x ^= a[i]; else { tot ++; a[i] = x; break; }
}
}
inline void inc(LL x) { for(int i = 0; i < 61; i ++) g[i][x>>i&1] ++; }//f[i]的每一位0/1的个数
inline void dfs(int u, int lst)
{
vis[u] = 1; inc(f[u]);
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; if(v == lst) continue;
if(!vis[v]) {
f[v] = f[u]^e[i].v;
dfs(v, u);
} else insert(f[v]^f[u]^e[i].v);//把环的异或值插入线性基
}
}
inline void cal()
{
LL tmp;
for(int i = 60; i >= 0; i --)
if(used>>i&1) {
tmp = g[i][0]*(g[i][0]-1)/2%mod;
tmp = (tmp+g[i][1]*(g[i][1]-1)/2%mod)%mod;
tmp = (tmp+g[i][1]*g[i][0]%mod)%mod;
ans = (ans+p[tot-1]*p[i]%mod*tmp%mod)%mod;
} else {
tmp = g[i][0]*g[i][1]%mod;
ans = (ans+p[tot]*p[i]%mod*tmp%mod)%mod;
}
memset(g, 0, sizeof g); memset(a, 0, sizeof a); used = 0; tot = 0;
}
int main()
{
n = read(), m = read();
p[0] = 1;
for(int i = 1; i <= 150; i ++) p[i] = 2LL*p[i-1]%mod;
for(int i = 1; i <= m; i ++) {
int x = read(), y = read(); LL z = read();
addedge(x, y, z); addedge(y, x, z);
}
for(int i = 1; i <= n; i ++)
if(!vis[i]) { dfs(i, 0); cal(); }
write(ans);
return 0;
}