[AGC004F]Namori题解

发布时间 2024-01-09 19:12:19作者: hubingshan

简要题意

思路

先考虑树的的情况,直接黑白染色,统计子树和的绝对值即可

再考虑奇环,发现这时会有两个同色相邻点,只需把多余的操作,在这两个点处理掉即可

最后考虑偶环,先断掉一条边,最后再考虑这条边的贡献,推一下柿子,就变成了初中数学题,取中位数即可

code

#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define int long long
int n,m,sum,A,B,ans,top,ji,k;
int h[N],w[N],K[N],q[N];
struct AB{
	int a,b,n;
}d[N*2];
void cun(int x,int y){
	d[++k]={x,y,h[x]},h[x]=k;
}
void dfs(int x,int fa){
	for(int i=h[x];i;i=d[i].n){
		int y=d[i].b;
		if(y==fa) continue;
		if(w[y]) ji=(w[x]==w[y]),A=x,B=y;
		else w[y]=-w[x],dfs(y,x);
	}
	sum+=w[x];
}
void dfs2(int x,int fa){
	for(int i=h[x];i;i=d[i].n){
		int y=d[i].b;
		if(y==fa||(x==A&&y==B)||(x==B&&y==A)) continue;
		dfs2(y,x);w[x]+=w[y],K[x]+=K[y];
	}
}
signed main(){
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(int i=1,x,y;i<=m;i++){
		scanf("%lld%lld",&x,&y);
		cun(x,y),cun(y,x);
	}
	if(n&1){
		printf("-1");
		return 0;
	}
	w[1]=1;dfs(1,0);
	if(sum&&!ji){
		printf("-1\n");
		return 0;
	}
	
	if(ji&&n==m) ans+=abs(sum>>1),w[A]-=(sum>>1),w[B]-=(sum>>1);
	else if(n==m) K[A]=1,K[B]=-1;
	dfs2(1,0);
	for(int i=1;i<=n;i++){
		if(K[i]) q[++top]=K[i]*w[i];
		else ans+=abs(w[i]);
	}
	q[++top]=0;
	sort(q+1,q+1+top);
	int zws=q[(top+1)/2];
	for(int i=1;i<=top;i++) ans+=abs(q[i]-zws);
	printf("%lld\n",ans);
	return 0;
}