题意:给定无向图,让你给点加权(1,2,3),使得每条边是两端点点权和维奇数。
思路:一个连通块是个二分图,判定二分图可以dfs,并查集,2-sat染色。 这里用的并查集(还可以带权并查集优化一下,或者干脆用dfs)。
计数的时候每个连通块单独考虑,我们从连通块的第一个点开始dfs,如果是该填奇数点,那么当前方案数*=2;分第一个点奇偶两种情况即可。
(多组输入一定注意初始化,这次CF多组输入好坑啊。。。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2000010; const int Mod=998244353; int Laxt[maxn],Next[maxn],To[maxn],cnt,num1,num2,vis[maxn],tot,ans; void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs(int u,int f,int x,int y) { tot++; vis[u]=1; if(x==1) num1=num1*2%Mod; if(y==1) num2=num2*2%Mod; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=f&&!vis[To[i]]) dfs(To[i],u,1-x,1-y); } } int fa[maxn]; int find(int x){ if(fa[x]==x) return x; return fa[x]=find(fa[x]); } int main() { int T,N,M,u,v; scanf("%d",&T); while(T--){ scanf("%d%d",&N,&M); rep(i,1,N) Laxt[i]=0; cnt=0; rep(i,1,N+N) fa[i]=i,vis[i]=0; bool F=true; rep(i,1,M){ scanf("%d%d",&u,&v); add(u,v); add(v,u); if(find(u)==find(v)) F=false; fa[find(u)]=find(v+N); fa[find(v)]=find(u+N); } if(!F) puts("0"); else { ans=1; rep(i,1,N) { if(!vis[i]){ num1=1; num2=1; tot=0; dfs(i,0,0,1); if(tot==1) ans=3LL*ans%Mod; else ans=1LL*ans*(num1+num2)%Mod; } } printf("%d ",ans); } } return 0; }