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
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值