题意:给出衣服无向带权图,问有多少对合法的$<u,v,s>$,要求$u$到$v$存在一条路径(不一定是简单路径)权值异或和等于$s$,并且$u<v$。求所有合法三元组的s的和。
思路:
参考了一篇大佬的博客。
这类题的核心思想就是,两点之间的所有可能的路径,都是由一条简单路径加上若干个环组成的。u,v两点所有路径的异或值的集合,等价于,u,v一条简单路径的异或值,与整个连通图的所有环组成的线性基异或的集合。
所以按位考虑每个二进制1给整幅图带来的价值。
特别要注意的一点是,在处理线性基的过程中,最多处理到63位,如果处理到64位及以上,当$i>=64$,某些$(x>>i)$,或者$(x<<i)$,就会发出许多诡异的错误,wa了很久。
#pragma GCC optimize (2) #pragma G++ optimize (2) #pragma comment(linker, "/STACK:102400000,102400000") #include<bits/stdc++.h> #include<cstdio> #include<vector> #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,b,a) for(int i=b;i>=a;i--) #define clr(a,b) memset(a,b,sizeof(a)) #define pb push_back #define pii pair<int,int > using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; ll rd() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=100010; const ll mod=1e9+7; int n,m; struct edge{ int to; ll w; }; vector<edge >ve[maxn]; int vis[maxn]; ll del[maxn],p[70],siz,num[70],ans=0,tot=0; void init(){ rep(i,1,n){ ve[i].clear(); vis[i]=0; } ans=0,siz=0,clr(p,0); } bool insert(ll x){ dep(i,63,0){ if((x>>i)&1){ if(!p[i]){ p[i]=x; return true; } x^=p[i]; } } return false; } void dfs(int u,ll res){ del[u]=res; for(ll i=63;i>=0;i--){ if(((res>>i)&1)){ num[i]++; } } tot++; vis[u]=1; for(auto &st:ve[u]){ if(!vis[st.to]){ dfs(st.to,res^st.w); }else{ if(insert(res^st.w^del[st.to])){ siz++; } } } } int main(){ while(cin>>n>>m){ init(); rep(i,1,m){ int u,v; ll w; u=rd(),v=rd(),w=rd(); ve[u].pb({v,w}); ve[v].pb({u,w}); } rep(u,1,n){ if(!vis[u]){ tot=0; clr(p,0),siz=0; clr(num,0); dfs(u,0); dep(i,63,0){ bool ok=0; dep(j,63,0){ if((p[j]>>i)&1)ok=1; } if(ok){ ans=(ans+tot*(tot-1)/2%mod*((1ll<<(siz-1))%mod)%mod*((1ll<<i)%mod)%mod)%mod; }else{ ans=(ans+num[i]*(tot-num[i])%mod*((1ll<<siz)%mod)%mod*((1ll<<i)%mod)%mod)%mod; } } } } printf("%lld ",ans); } }