https://vjudge.net/contest/176221#problem/G
题意:给出一个二分图的两个顶点集合,每个顶点集合的大小为n,输入v1,w1,v2,w2,表示集合U中的i顶点与集合V中的v1,v2顶点相连,且边的权值为w1,w2。求两个集合的所有完备匹配的权值之和。一个完备匹配的权值为该匹配所有边的权值相乘,且数据保证至少存在一个完美匹配。
#include<algorithm>
#include<vector>
#include<cstring>
#include<string>
#include<iomanip>
#include<cstdio>
#include<stack>
#include<iostream>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
#define sf scanf
#define pf printf
#define mem(a,b) memset(a,b,sizeof(a));
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define bug1 puts("bug1");
#define bug2 puts("bug2");
#define bug3 puts("bug3");
#define N 600010
#define M 1200020
#define mod 998244353
#define ULL unsigned long long
#define LL long long
#define inf 0x3f3f3f3f
//2017年08月05日13:00:00
LL part[2];
int fst[N],du[N],vv[M],vis[N],cost[M],nxt[M],e;
bool use[M];
void add(int u,int v,int w ){
vv[e]=v;nxt[e]=fst[u];cost[e]=w;fst[u]=e++;
}
void dfs(int u,int flag){
vis[u]=1;
for(int i=fst[u];~i;i=nxt[i]){
int v=vv[i];
if(use[i])continue;
part[flag]=(part[flag]*cost[i])%mod;
use[i^1]=use[i]=true;
dfs(v,flag^1);
}
}
int main(){
int T ;sf("%d",&T);
while(T--){
int n;sf("%d",&n);
mem(fst,-1);e=0;
mem(du,0);mem(vis,0);mem(use,0);
rep(i,1,n){
int v1,w1,v2,w2;sf("%d%d%d%d",&v1,&w1,&v2,&w2);
add(i,v1+n,w1);add(v1+n,i,w1);
add(i,v2+n,w2);add(v2+n,i,w2);
du[v1+n]++;du[v2+n]++;
du[i]+=2;
}
queue<int>q;
for(int i=n+1;i<=2*n;++i){
if(du[i]==1){q.push(i);}
}
LL ans=1;
mem(use,false);
while(!q.empty()) {
int v=q.front();
q.pop(),vis[v]=1;
for(int i=fst[v]; ~i; i=nxt[i]) {
if(use[i])continue;
use[i]=use[i^1]=true;
vis[vv[i]]=1;
ans=(ans*cost[i])%mod;
for(int j=fst[vv[i]]; ~j; j=nxt[j]) {
use[j]=use[j^1]=true;
--du[vv[j]];
if(du[vv[j]]==1)
q.push(vv[j]);
}
}
}
for(int i=1;i<=n;++i){
part[1]=part[0]=1;
if(!vis[i]){
dfs(i,0);
ans=(ans*(part[0]+part[1])%mod)%mod;
}
}
pf("%lld\n",ans);
}
}