1. 程式人生 > >codeforces 724G. Xor-matic Number of the Graph

codeforces 724G. Xor-matic Number of the Graph

G. Xor-matic Number of the Graph
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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-simple, i.e. it can visit the same vertices and edges multiple times) between vertices u and v such that xor of all numbers written on the edges of this path is equal to s. When we compute the value s for some path, each edge is counted in xor as many times, as it appear on this path. It’s not hard to prove that there are finite number of such triples.

Calculate the sum over modulo 109 + 7 of the values of s over all interesting triples.

Input
The first line of the input contains two integers n and m (1 ≤ n ≤ 100 000, 0 ≤ m ≤ 200 000) — numbers of vertices and edges in the given graph.

The follow m lines contain three integers ui, vi and ti (1 ≤ ui, vi ≤ n, 0 ≤ ti ≤ 1018, ui ≠ vi) — vertices connected by the edge and integer written on it. It is guaranteed that graph doesn’t contain self-loops and multiple edges.

Output
Print the single integer, equal to the described sum over modulo 109 + 7.

Examples
input
4 4
1 2 1
1 3 2
2 3 3
3 4 1
output
12
input
4 4
1 2 1
2 3 2
3 4 4
4 1 8
output
90
input
8 6
1 2 2
2 3 1
2 4 4
4 5 5
4 6 3
7 8 5
output
62
Note
In the first example the are 6 interesting triples:

(1, 2, 1)
(1, 3, 2)
(1, 4, 3)
(2, 3, 3)
(2, 4, 2)
(3, 4, 1)
The sum is equal to 1 + 2 + 3 + 3 + 2 + 1 = 12.
In the second example the are 12 interesting triples:

(1, 2, 1)
(2, 3, 2)
(1, 3, 3)
(3, 4, 4)
(2, 4, 6)
(1, 4, 7)
(1, 4, 8)
(2, 4, 9)
(3, 4, 11)
(1, 3, 12)
(2, 3, 13)
(1, 2, 14)
The sum is equal to 1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 + 11 + 12 + 13 + 14 = 90.

【分析】

天天把陣列開小我也是醉了…
這個題看上去非常麻煩…題目要求把任意兩點之間所有路徑的兩兩不同的異或和累加進入答案裡面。
異或和當然要用到線性基…
路徑異或和當然要找環…

於是我們順(hao)理(wu)成(luo)章(ji)的對每個連通塊進行一遍dfs,獲得了一棵dfs樹,每個點的一條任意路徑的xor值和所有的環的路徑異或值,把環的路徑異或值搞出來線性基。接下來問題就比較好玩了。

對於一個聯通塊內的所有點,兩兩都要統計貢獻進入答案。這時候我們根據xor的特徵採用了一個非常有效的辦法:二進位制逐位統計貢獻。

對於所有點的xor值,假設當前統計的是二進位制的從小到大第k位,那麼此時的所有點的xor可以分為兩類:第k位為0,第k位為1。

首先考慮第k位同為0或同為1的情況,這種情況下兩點路徑第k位異或和為0,所以線上性基中必須要有一個線性基第k位為1,異或上兩點路徑,貢獻才可以加入答案。如果存在,那麼對答案的貢獻為2k2r1 (r為線性基的個數),因為我們把一個第k位為1的線性基挑出來,剩下的r-1個線性基可以選或者不選,異或以後第k位為0或1,根據第k位是0還是1唯一確定挑出來的線性基選或者不選。

第k位不同的情況也是如此考慮。

【程式碼】

//codeforces 724G. Xor-matic Number of the Graph
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=400005;
const int mod=1e9+7;
ll ans;
int n,m,num,cir,r,cnt;
int head[mxn],que[mxn];
struct edge {int to,next;ll w;} f[mxn<<2];
ll p[105],circle[mxn],dis[mxn],dig[2],pw[105];
inline void add(int u,int v,ll w)
{
    f[++cnt].to=v,f[cnt].w=w,f[cnt].next=head[u],head[u]=cnt;
}
inline void dfs(int u,int fa,ll now)
{
    dis[u]=now,que[++num]=u;
    for(int i=head[u];i;i=f[i].next)
    {
        int v=f[i].to;
        if(v==fa) continue;
        if(dis[v]==-1) dfs(v,u,dis[u]^f[i].w);
        else circle[++cir]=dis[u]^dis[v]^f[i].w;
    }
}
inline void init()
{
    int i,j;r=0;
    memset(p,0,sizeof p);
    fo(i,1,cir)
    {
        ll x=circle[i];
        for(j=62;j>=0;j--)
        {
            if(!(x>>j)) continue;
            if(!p[j]) {p[j]=x;break;}
            x^=p[j];
        }
    }
    fo(j,0,62) if(p[j]) r++;
}
inline void calc()
{
    init();
    int i,j;
    for(j=0;j<=62;j++)
    {
        bool flag=0;dig[0]=dig[1]=0;
        fo(i,1,num) dig[(dis[que[i]]>>j)&1]++;
        fo(i,0,62) if((p[i]>>j)&1) {flag=1;break;}
        ll now=(dig[0]*(dig[0]-1)/2+dig[1]*(dig[1]-1)/2)%mod;
        if(flag)
        {
            if(r) now=now*pw[r-1]%mod;
            now=now*pw[j]%mod;
            ans=(ans+now)%mod;
        }
        now=dig[0]*dig[1]%mod;
        if(flag) {if(r) now=now*pw[r-1]%mod;}
        else now=now*pw[r]%mod;
        now=now*pw[j]%mod;
        ans=(ans+now)%mod;
//      printf("%d %lld\n",j,ans);
    }
}
int main()
{
    int i,j,u,v;ll w;
    memset(dis,-1,sizeof dis);
    pw[0]=1;fo(j,1,100) pw[j]=pw[j-1]*2%mod;
    scanf("%d%d",&n,&m);
    fo(i,1,m)
    {
        scanf("%d%d%lld",&u,&v,&w);
        add(u,v,w),add(v,u,w);
    }
    fo(i,1,n) if(dis[i]==-1)
    {
        num=cir=0;
        dfs(i,0,0);
        calc();
    }
    printf("%lld\n",ans);
    return 0;
}
/*
4 4
1 2 1
1 3 2
2 3 3
3 4 1
*/