这题转化太巧妙,将边权转化成点权,根据性质,在一个环内,每个点都会影响两条边,也就是说,将两点之间的边权设置为两个点权的异或值,那么答案肯定为0.因为每个点都异或两次
这样的话,假如没有设计过某些边权,那么答案就是所有点的取值/2,因为当所有0变成1所有1变成0,那么边权是一毛一样的。
考虑有某些边权是存在的,那么我们就要把这些边权所组成的连通块找出来,在某一个全部由存在边权的连通块中,一个点确定,所有点确定,因此可变的只有这个点,答案就要除以2的k-1次,k是连通块中点的个数,这符合除法定理。另外还要判断矛盾,也就是一开始的图就不符合答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; const ll mod=998244353; int h[N],ne[N],e[N],w[N],idx; int c[N]; int n,m; int sum; void add(int a,int b,int c){ e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++; } int dfs0(int u,int x){ c[u]=x; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(w[i]==-1) continue; if(c[j]!=-1&&(x^w[i])!=c[j]) return 0; if(c[j]==-1&&!dfs0(j,x^w[i])) return 0; } return 1; } void dfs1(int u,int fa){ c[u]=1; sum++; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; if(c[j]==-1){ dfs1(j,u); } } } void dfs2(int u,int fa){ c[u]=1; int i; sum--; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; if(w[i]!=-1){ if(!c[j]) dfs2(j,u); } } } int main(){ int i; cin>>n>>m; memset(c,-1,sizeof c); memset(h,-1,sizeof h); for(i=1;i<=m;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } int flag=0; for(i=1;i<=n;i++){ if(c[i]==-1){ if(!dfs0(i,1)){ cout<<0<<endl; return 0; } } } memset(c,-1,sizeof c); for(i=1;i<=n;i++){ if(c[i]==-1){ dfs1(i,-1); sum-=1; } } memset(c,0,sizeof c); for(i=1;i<=n;i++){ if(!c[i]){ dfs2(i,-1); sum+=1; } } ll k=1; for(i=1;i<=sum;i++){ k=(k*2)%mod; } cout<<k<<endl; }