哪一天她能重回我身边 换根+基环树

Solution

将每个卡片反面数字向正面数字(值域(1~2n))建边,若能通过翻转边的方向使每个点的入度不大于(1),则达到目标
对于’使每个点的入度不大于(1),我们让其构成一棵树,(根节点入度为(0)
最终答案:最小次数=(sum各联通块最小次数),方案数=(prod各联通块最小次数的个数)
对于每个联通块,边数(m),点数(n)

(m==n-1)
(dfs)出联通块中任意一点(x)(f[x]),即以(x)为根,总翻转次数。
(dfs)一遍得出每个点的(f[]),取个(min),并找一下有几个(min)

(m==n)
基环树,只有两种情况,选一条环上的边((ed_{id})),符合要求的图的根节点只能是这条边两端端点((S和T))之一
先忽略这条边,最后把这条边指向根节点,算出(f[S],f[T]).取(min)及找(min)个数((1或2))

(m>n) 一定无法达到

处理的时候建成双向边,(cnt)初始为1,用来判断父边和判断正面向反面的边。

code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cctype>
using namespace std;
char buf[1<<20],*p1,*p2;
#define rint register int
#define gc() (p1==p2?(p2=buf+fread(p1=buf,1,1<<20,stdin),p1==p2?EOF:*p1++):*p1++)
#define read() ({
	rint x=0;register char ch=gc();
	while(!isdigit(ch)) ch=gc();
	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch&15),ch=gc();
	x;
})
const int maxn=2e5+5,M=998244353;
int f[maxn];
int S,T,ed_id;
int ans,ans_cnt;
int n,cnt,head[maxn];
int node_cnt,edge_cnt;
bool vis[maxn],jud;
struct Edge{
	int to,next;
}e[maxn*2];
vector < int > vec;
void Init(){
	cnt=1,jud=0,ans=0,ans_cnt=1;
	memset(head,0,sizeof head);
	memset(vis,0,sizeof vis);
	memset(f,0,sizeof f);
}
void Aedge(rint x,rint y){
	e[++cnt].to=y;
	e[cnt].next=head[x];
	head[x]=cnt;
}
void dfs(rint x){
	vis[x]=1,node_cnt++;
	for(rint i=head[x];i;i=e[i].next){
		const rint y=e[i].to;
		edge_cnt++;
		if(vis[y]) continue;
		dfs(y);
	}
}
void dfs1(rint x,rint prt){
	vis[x]=1;
	for(rint i=head[x];i;i=e[i].next){
		const rint y=e[i].to;
		if(y==prt) continue;
		if(vis[y]) S=x,T=y,ed_id=i;
		else{
			dfs1(y,x);
			f[x]+=f[y]+(i&1);
		}
	}
}
void dfs2(rint x,rint prt){
	vec.push_back(f[x]);
	for(rint i=head[x];i;i=e[i].next){
		const rint y=e[i].to;
		if(y==prt||i==ed_id||i==(ed_id^1)) continue;
		f[y]=f[x]+((i&1)?-1:1);
		dfs2(y,x);
	}
}
int main(){ 
	//freopen("back10.in","r",stdin);
	//freopen("1.out","w",stdout);
	freopen("back.in","r",stdin);
	freopen("back.out","w",stdout);
	rint cs=read();
	while(cs--){
		Init();
		n=read();
		for(rint i=1,x,y;i<=n;++i){
			x=read(),y=read();
			Aedge(y,x),Aedge(x,y);
		}
		for(rint i=1;i<=n*2;++i){
			if(vis[i]) continue;
			node_cnt=0,edge_cnt=0;
			dfs(i);
			if(edge_cnt/2>node_cnt){ jud=1;break; }
		}
		if(jud){ printf("-1 -1
");continue; }
		memset(vis,0,sizeof vis);
		for(rint i=1;i<=n*2;++i){ // 枚举每个点作为根节点指向儿子,以保证每点入度不大于1
			if(vis[i]) continue;
			vec.clear();
			S=0,T=0,ed_id=0;
			dfs1(i,0);
			dfs2(i,0);
			rint cc=0;
			if(!ed_id){
				sort(vec.begin(),vec.end());
				for(rint j=0;j<vec.size();++j){
					if(vec[j]==vec[0]) ++cc;
					else break;
				}
				(ans+=vec[0])%=M;
				ans_cnt=1ll*ans_cnt*cc%M;
			}
			else{
				const rint opt=ed_id&1;
				if(f[S]+(!opt)==f[T]+opt) cc=2; // 注意不要'if(~~) f[S]++; else f[T]++; ',可能S==T
				else cc=1;
				(ans+=min(f[S]+(!opt),f[T]+opt))%=M;
				ans_cnt=1ll*ans_cnt*cc%M;
			}
		}
		printf("%d %d
",ans,ans_cnt);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Lour688/p/13801157.html