一、题目
二、解法
样例解释给了一点提示,我们可以先把毫无影响的 x x x提出来(不是任何一个 c [ u ] ⊕ c [ v ] c[u]\oplus c[v] c[u]⊕c[v])
然后可以把按 c [ u ] ⊕ c [ v ] c[u]\oplus c[v] c[u]⊕c[v]把所有边分类,只有同一类的边会相互影响,所以把同一类的边同时连起来,每一个连通块内的点必须同时选或者同时不选,所以方案数是 2 2 2的连通块数次方,把不同类别的方案求和即可。
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 500005;
const int MOD = 1e9+7;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,ans,cnt,sum,fa[M],c[M];
struct node
{
int u,v,c;
bool operator < (const node &b) const
{
return c<b.c;
}
}a[M];
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int u,int v)
{
int x=find(u),y=find(v);
if(x!=y) fa[x]=y,sum--;
}
int qkpow(int a,int b)
{
int r=1;
while(b>0)
{
if(b&1) r=r*a%MOD;
a=a*a%MOD;
b>>=1;
}
return r;
}
signed main()
{
n=read();m=read();k=read();
for(int i=1;i<=n;i++)
c[i]=read(),fa[i]=i;
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
a[i]=node{u,v,c[u]^c[v]};
}
sort(a+1,a+1+m);
for(int i=1,j=1;i<=m;)
{
cnt++;sum=n;
for(;j<=m;j++)
{
if(a[i].c!=a[j].c) break;
merge(a[j].u,a[j].v);
}
ans=(ans+qkpow(2,sum))%MOD;
for(;i<j;i++)
{
fa[a[i].u]=a[i].u;
fa[a[i].v]=a[i].v;
}
}
ans+=(qkpow(2,k)-cnt)*qkpow(2,n);
printf("%lld\n",(ans%MOD+MOD)%MOD);
}