题目大意:
给定一个无向图,设三元组 (u,v,s) ( u , v , s ) 为从 u u 到的一条路径,每条边的权值的异或为 s s 。求所有的三元组的的和。
思路:
我们先固定起点和终点,发现
s
s
的集合就是从到
v
v
的一条路径异或上这个联通块里的所有的环构成的异或集合(因为图可能不是联通的),可以理解为绕环走一圈然后中间的部分走了两次。然后对于每一个固定的,我们只需要构造出那个联通块的所有的环的线性基就好了。
但是题目球求的是所有的
(u,v,s)
(
u
,
v
,
s
)
,考虑怎么快速地求出从
u
u
到的异或和,我们可以从一个固定节点进行dfs,然后记录下从根节点到每一个节点的异或和,不难发现,
sum[x]⊕sum[y]
s
u
m
[
x
]
⊕
s
u
m
[
y
]
即从
x
x
到的路径的异或和。
所以对于每一个联通块,答案就是
∑i,jsum[i]⊕sum[j](i≠j)
∑
i
,
j
s
u
m
[
i
]
⊕
s
u
m
[
j
]
(
i
≠
j
)
和整个线性基的异或和的算术和了。
一开始想到这里我还愣住了,不知道怎么求异或和的算术和。。。。然后发现按位考虑,组合数学乱搞一波就没了。
代码是写的真的乱。。。。还因为忘记对逆元去取一个模直接炸掉了。
/*==============================
* Author : ylsoi
* Problem : CF724G
* Algorithm : Linear Basis
* Time : 2018.6.14
* ============================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
freopen("CF724G.in","r",stdin);
freopen("CF724G.out","w",stdout);
}
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=1e5+10;
const int maxm=2e5+10;
const ll mod=1e9+7;
int n,m,beg[maxn],cnte=1;
ll ans;
struct edge{int to,last,from;ll w;}E[maxm*2];
void add(int u,int v,ll w){
++cnte;
E[cnte].to=v;
E[cnte].last=beg[u];
beg[u]=cnte;
E[cnte].w=w;
E[cnte].from=u;
}
ll c[100],inv[100];
ll qpow(ll x,ll b){
ll base=x,ret=1ll;
while(b){
if(b&1)ret=ret*base%mod;
base=base*base%mod;
b>>=1;
}
return ret;
}
#define C(i,j) (c[i]*inv[i-j]%mod*inv[j]%mod)
ll b[70];
void insert(ll x){
DREP(i,62,1){
ll p=1ll<<(i-1);
if(!(p&x))continue;
if(!b[i]){
b[i]=x;
break;
}
x^=b[i];
}
}
ll sum[maxn];
bool vis[maxn];
ll cnt[70][2];
void dfs(int u,int fr){
if(vis[u]){
insert(sum[E[fr].from]^sum[u]^E[fr].w);
return;
}
vis[u]=1;
sum[u]=sum[E[fr].from]^E[fr].w;
DREP(i,62,1){
ll p=1ll<<(i-1);
++cnt[i][(p&sum[u])!=0];
}
MREP(i,u){
if(i==(fr^1))continue;
int v=E[i].to;
dfs(v,i);
}
}
void cal(){
DREP(i,62,1){
ll p=1ll<<(i-1);
int c0=0,c1=0;
REP(j,1,62)if(b[j])
b[j]&p ? ++c1 : ++c0;
REP(j,0,c1){
if(j%2==0)ans=(ans+qpow(2,i-1)*C(c1,j)%mod*qpow(2,c0)%mod*cnt[i][0]%mod*cnt[i][1]%mod)%mod;
else ans=(ans+qpow(2,i-1)*C(c1,j)%mod*qpow(2,c0)%mod* ( cnt[i][0]%mod*(cnt[i][0]-1)%mod*qpow(2,mod-2)%mod + cnt[i][1]*(cnt[i][1]-1)%mod*qpow(2,mod-2)%mod )%mod )%mod;
}
}
}
void work(){
REP(i,1,n){
if(vis[i])continue;
mem(cnt);
mem(b);
dfs(i,0);
cal();
}
printf("%lld\n",ans);
}
void init(){
scanf("%d%d",&n,&m);
REP(i,1,m){
int u,v;ll w;
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
c[0]=1ll;
REP(i,1,70)c[i]=c[i-1]*i%mod;
inv[70]=qpow(c[70],mod-2);
DREP(i,69,0)inv[i]=inv[i+1]*(i+1)%mod;
}
int main(){
File();
init();
work();
return 0;
}