Codeforces 724G Xor-matic Number of the Graph 線性基
阿新 • • 發佈:2019-01-06
題意
給一個n個點m條邊的無向圖,邊有邊權V,定義一個三元組是合法的當且僅當存在一條從到的路徑滿足這條路徑上邊權的異或和恰好為。問所有合法三元組的的和。
分析
先把原圖的一棵dfs樹找出來。
考慮一組點對,他們之間的所有路徑的權值並顯然是他們在dfs樹上的路徑,然後再任意異或上一些由返祖邊組成的環。
那麼我們就對所有返祖邊組成的環的權值建線性基,也就是我們可以異或上線性基中的若干個數來得到某個權值。
現在對每一位單獨討論,設線性基中有個數該位是,有個數該位是,接下來分兩種情況:
若,那麼這個數不管怎麼選都不會影響結果,那麼就樹形dp一遍求出有多少條路徑的異或和為。
若,要想使得結果對答案有貢獻,當兩端點之間路徑異或和為,就要從這個數中選偶數個數出來,反之則要選奇數個數出來,不難發現係數都是,所以滿足的方案就是
時間複雜度。
程式碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=100005;
const int MOD=1000000007;
int n,m,cnt,last[N],t0[N],t1[N],now,sum,dep[N],a[N],ans,tot,po[N];
bool vis[N],flag;
LL bin[65],bas[65],val[N];
struct edge{int to,next;LL w;}e[N*4];
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;
}
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
void ins(LL x)
{
for (int i=60;i>=0;i--)
if (x&bin[i])
{
if (!bas[i])
{
bas[i]=x;
break;
}
else x^=bas[i];
}
}
void dfs(int x)
{
vis[x]=1;a[++tot]=x;
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to])
{
if (dep[e[i].to]<dep[x]) ins(val[x]^val[e[i].to]^e[i].w);
continue;
}
val[e[i].to]=val[x]^e[i].w;
dep[e[i].to]=dep[x]+1;
dfs(e[i].to);
}
}
void calc(int x)
{
vis[x]=1;t0[x]=1;t1[x]=0;
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to]) continue;
calc(e[i].to);
if (e[i].w&bin[now]) std::swap(t1[e[i].to],t0[e[i].to]);
(sum+=(LL)t0[x]*t1[e[i].to]%MOD)%=MOD;
(sum+=(LL)t1[x]*t0[e[i].to]%MOD)%=MOD;
t0[x]+=t0[e[i].to];t1[x]+=t1[e[i].to];
}
}
void solve(int rt)
{
memset(bas,0,sizeof(bas));
tot=0;dfs(rt);
for (int i=0;i<=60;i++)
{
sum=0;now=i;
for (int j=1;j<=tot;j++) vis[a[j]]=0;
calc(rt);
int s0=0,s1=0;
for (int j=0;j<=60;j++)
if (bas[j])
{
if (bas[j]&bin[i]) s1++;
else s0++;
}
if (!s1) (ans+=(LL)bin[i]%MOD*sum%MOD*ksm(2,s0)%MOD)%=MOD;
else (ans+=(LL)bin[i]%MOD*po[s0+s1-1]%MOD*((LL)tot*(tot-1)/2%MOD)%MOD)%=MOD;
}
}
int main()
{
bin[0]=1;
for (int i=1;i<=60;i++) bin[i]=bin[i-1]*2;
scanf("%d%d",&n,&m);
po[0]=1;
for (int i=1;i<=n;i++) po[i]=po[i-1]*2%MOD;
for (int i=1;i<=m;i++)
{
int x,y;LL z;scanf("%d%d%lld",&x,&y,&z);
addedge(x,y,z);
}
for (int i=1;i<=n;i++)
if (!vis[i]) solve(i);
printf("%d",ans);
return 0;
}