HDU 6109 数据分割(并查集+set维护)

 题目:http://acm.hdu.edu.cn/showproblem.php?pid=6109

题意:给n行数,a,b,e  e为0表示两个数不相等,e为1表示相等。

要求划分数据 ,让每一组数据都不符合,去掉最后一个就符合,

题解:

相等的就在一个集合,集合之间有边表示两个集合不相等

例如给出a,b,e, 并查集初始化后祖先为x,y

若e==1:

  1. x==y时,a==b,在一个集合,不做处理
  2. x!=y,不在一个集合, 若集合x和集合y有边,矛盾 有边表示不相等,但是现在e==1,说明a==b,输出答案(加入队列)
  3. x!=y,不在一个集合,  若集合x和集合y没有边,就合并两个集合

若e==0:

  1. x==y时,两个不相等的数在一个集合,矛盾 ,输出答案,初始化并查集,下一次分割
  2. x!=y , a!=b,两个数不在一个集合,成立,给他们加一条边,以这种方式存储数据
#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int f[maxn],a[maxn],b[maxn],e[maxn];
set<int> G[maxn];
vector<int> ans;
int n;
int fa(int x)
{
	return f[x]==x?x:f[x]=fa(f[x]);
}
void init()
{
	for(int i=0;i<n;i++)
	 	f[i]=i,G[i].clear(); 
}
void solve()
{
	int cnt=0;
	for(int i=0;i<n;i++)
		{
			cnt++;
			int x=fa(a[i]),y=fa(b[i]);
			if(e[i])//a==b
			{
				if(x==y)continue;
				else
				{
					if(G[x].find(y)!=G[x].end())//a==b x!=y 相等不在一个集合 
					//集合之间有边   矛盾 
					{
						ans.push_back(cnt);
						cnt=0;
						init();
					}else//集合无边 并查集合并 
					{
						set<int>::iterator it;
						for(it=G[x].begin();it!=G[x].end();it++)
							{//连接x集合的边都删除 连接y 
								G[y].insert(*it);
								G[*it].erase(x);
								G[*it].insert(y);
							}
						G[x].clear();
						f[x]=y;//合并集合 x,y 
					}
				} 
				
			}
			else//a!=b 
			{
				if(x==y)//不相等的数在一个集合 矛盾 
				{
					ans.push_back(cnt);
					cnt=0;
					init();
				}else//不在一个集合  两个集合加一条边 
				{
					G[x].insert(y),G[y].insert(x);
				}
			}
		}
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%d %d %d",&a[i],&b[i],&e[i]);
	
	init();
			
	solve();
	int sz=ans.size();
	printf("%d\n",sz);
	for(int i=0;i<sz;i++)
		printf("%d\n",ans[i]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wym_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值