【线性基】CF724G Xor-matic Number of the Graph

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89737908

【题目】
CF
给定一幅带边权无向图,定义一个三元组 ( u , v , w ) (u,v,w) 是有趣的,当且仅当存在一条 u u v v 的路径(可以非简单),满足路径异或值为 w w
求所有有趣三元组 w w 之和。
n , m 2 × 1 0 5 , w 1 0 18 n,m\leq 2\times 10^5,w\leq 10^{18}

【解题思路】
首先求出一棵 DFS \text{DFS} 树,将所有环的权丢进线性基,那一条路径 ( u , v ) (u,v) 的可行权就是两点到根距离异或值再异或上任意个环的权值。

考虑对每一位分开计算,设线性基大小为 S S 。那么若线性基中某一位有 1 1 ,显然这一位不论 u , v u,v 怎么取都能有贡献,因此就是 ( n 2 ) 2 k 2 S 1 {n\choose 2}\cdot 2^k\cdot 2^{S-1} 。而若没有 1 1 ,则需要路径这一位为 0 0 1 1 的两个组合,那么答案就是 c n t 2 k 2 S cnt\cdot 2^k\cdot 2^S

【参考代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10,M=61,mod=1e9+7;

ll read()
{
	ll ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

namespace Math
{
	ll fc[M],pw[M];
	ll C(ll x){return x*(x-1)/2%mod;}
	void init(){fc[0]=pw[0]=1;for(int i=1;i<M;++i)fc[i]=fc[i-1]<<1,pw[i]=fc[i]%mod;}
	struct Linear_Basis
	{
		int sz,hv[M];ll A[M];
		void clear(){sz=0;memset(A,0,sizeof(A));memset(hv,0,sizeof(hv));}
		void insert(ll x)
		{
			for(int i=0;i<M;++i) hv[i]|=(x&fc[i]?1:0);
			for(int i=M-1;~i;--i) if(x&fc[i])
			{
				if(!A[i]) {A[i]=x;++sz;break;}
				else x^=A[i];
			}
		}
	}B;
}
using namespace Math;

namespace Graph
{
	int tot,S,head[N],vis[N],cnt[M];
	ll dis[N];
	struct Tway{int v,nex;ll w;}e[N<<2];
	void add(int u,int v,ll w)
	{
		e[++tot]=(Tway){v,head[u],w};head[u]=tot;
		e[++tot]=(Tway){u,head[v],w};head[v]=tot;
	}
	void dfs(int x,int ff)
	{
		vis[x]=1;++S;
		for(int i=0;i<M;++i)if(dis[x]&fc[i])++cnt[i];
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].v;
			if(v==ff) continue;
			//cerr<<x<<" "<<v<<" "<<vis[v]<<" "<<dis[x]<<" "<<dis[v]<<" "<<e[i].w<<endl;
			if(vis[v]) {B.insert(dis[v]^dis[x]^e[i].w);continue;}
			dis[v]=dis[x]^e[i].w;dfs(v,x);
		}
	}
}
using namespace Graph;

int main()
{
#ifdef Durant_Lee
	freopen("CF724G.in","r",stdin);
	freopen("CF724G.out","w",stdout);
#endif
	init();int n=read(),m=read();ll ans=0;
	for(int i=1,u,v;i<=m;++i) u=read(),v=read(),add(u,v,read());
	for(int x=1;x<=n;++x) if(!vis[x])
	{
		S=0;memset(cnt,0,sizeof(cnt));B.clear();dfs(x,0);
		//for(int i=0;i<M;++i) printf("%d ",cnt[i]); puts("");
		for(int i=0;i<M;++i) 
		{
			if(B.hv[i]) ans=(ans+pw[i]*C(S)%mod*pw[B.sz-1]%mod)%mod;
			else ans=(ans+pw[i]*cnt[i]%mod*(S-cnt[i])%mod*pw[B.sz]%mod)%mod;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/89737908