【构造】劲爆题

题意:

在这里插入图片描述


分析

如果可以使得二分图的某一侧全为0,另一侧全不为0,那么一定可以满足条件。

显然,左侧点权之和=右侧点权之和(mod 3)

因此,不为0的一侧就必须满足点权和mod 3=0

这个限制是非常弱的:如果这一侧总点数为 3 ∗ k 3*k 3k,那么直接所有都为1即可。

如果为 3 ∗ k + 1 3*k+1 3k+1,那么拿两个数来换成2.

如果为 3 ∗ k + 2 3*k+2 3k+2,那么拿一个数来换成2.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
int n1,n2,m;
int ans[MAXN];
vector<pair<int,int> >a[MAXN];
vector<int> p1[MAXN],p2[MAXN];
int col[MAXN];
int fa[MAXN];
int get_fa(int x){
	if(fa[x]==0)
		return x;
	fa[x]=get_fa(fa[x]);
	return fa[x];	
}
void dfs(int x,int fax,int id){
	for(int i=0;i<int(a[x].size());i++){
		int u=a[x][i].first;
		if(u==fax)
			continue;
		dfs(u,x,a[x][i].second);
		col[x]-=col[u];
	}
	ans[id]=(col[x]%3+3)%3;
}
int main(){
	SF("%d%d%d",&n1,&n2,&m);	
	int u,v;
	for(int i=1;i<=m;i++){
		SF("%d%d",&u,&v);
		v+=n1;
		int u1=get_fa(u),v1=get_fa(v);
		if(u1!=v1){
			a[u].push_back(make_pair(v,i));
			a[v].push_back(make_pair(u,i));	
			fa[u1]=v1;
		}
	}
	for(int i=1;i<=n1;i++)
		p1[get_fa(i)].push_back(i);
	for(int i=n1+1;i<=n1+n2;i++)
		p2[get_fa(i)].push_back(i);
	for(int i=1;i<=n1+n2;i++)
		if(fa[i]==0){
			if(p1[i].size()==1&&p2[i].size()==1){
				PF("-1");
				return 0;
			}
			if(p1[i].size()==1)
				swap(p1[i],p2[i]);
			for(int j=0;j<int(p1[i].size());j++)
				col[p1[i][j]]=1;
			if(p1[i].size()%3)
				col[p1[i][0]]++;
			if(p1[i].size()%3==1)
				col[p1[i][1]]++;
			dfs(i,0,0);
		}
	for(int i=1;i<=m;i++)
		PF("%d ",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值