图的异或 dfs树+线性基

来源:互联网 发布:边缘融合软件 破解 编辑:程序博客网 时间:2024/06/06 07:27

题意

给出一个无向图,边有边权。定义一条路径的权值为路径上所有边的异或和。问从s到t的所有路径中,所有不同的权值的和是多少。答案模1e9+7输出。
n,m<=100000,val<2^60

分析

zw大爷告诉我,碰到这种图论题首先要想到dfs树或bfs树。

这题的话,可以先建出dfs树,设s到t的路径权值为dt。对于每一条返祖边,显然我们可以通过这条返祖边,来使答案异或上这个环的权值。那么我们就把所有环的权值扔到线性基里面,然后分别讨论每一位的贡献即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=100005;const int MOD=1000000007;int n,m,vis[N],cnt,last[N],a1,s,t;LL bin[65],bas[65],val[N],a[N];struct edge{int to,next;LL w;}e[N*2];void addedge(int u,int v,LL w){    e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;    e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;}void dfs(int x){    vis[x]=1;    for (int i=last[x];i;i=e[i].next)        if (!vis[e[i].to])        {            val[e[i].to]=val[x]^e[i].w;            dfs(e[i].to);        }        else a[++a1]=e[i].w^val[x]^val[e[i].to];}int main(){    freopen("xor.in","r",stdin);freopen("xor.out","w",stdout);    scanf("%d%d",&n,&m);    bin[0]=1;    for (int i=1;i<=60;i++) bin[i]=bin[i-1]*2;    for (int i=1;i<=m;i++)    {        int x,y;LL z;        scanf("%d%d%lld",&x,&y,&z);        addedge(x,y,z);    }    scanf("%d%d",&s,&t);    dfs(s);    int tot=0;    for (int i=1;i<=a1;i++)        for (int j=60;j>=0;j--)            if (a[i]&bin[j])            {                if (!bas[j])                {                    bas[j]=a[i];tot++;                    break;                }                else a[i]^=bas[j];            }    int ans=0;    for (int i=0;i<=60;i++)        if (bas[i]) (ans+=bin[i]%MOD*(bin[tot-1]%MOD)%MOD)%=MOD;        else        {            int flag=0;            for (int j=i+1;j<=60;j++)                if (bas[j]&bin[i])                {                    flag=1;break;                }            if (flag) (ans+=bin[i]%MOD*(bin[tot-1]%MOD)%MOD)%=MOD;            else if (val[t]&bin[i]) (ans+=bin[i]%MOD*(bin[tot]%MOD)%MOD)%=MOD;        }    printf("%d",ans);    return 0;}