HDU6109:并查集+set

HDU6109

题意:开始题目看来半天每看懂。。。

i,j表示某个数的编号,题目给你约束条件,以i,j为编号的数相等(e=1)或者不相等(e=0)。将这么多约束条件按顺序分组。

每一组满足约束条件矛盾,但是去掉最后一组就不矛盾了。求共有几组和每组的数量。就是这样~

题解:不知不觉~迷迷糊糊~就一次AC了

首先用并查集来维护。

1、如果之前两个数在一个集合里面(fx = fy),就表示这两个数相同,如果e=0,则约束条件表示这两个数不相同,则矛盾。因此要init更新这个新的组一下。有些小朋友就要问why?假如现在a,b,c一组,后面a,b,d也可能一组,为了不影响后面的,所以要更新。

其次用set维护与当前元素不相同的所有元素。

2、如果之前两个数不在一个集合里(fx != fy),如果约束条件给出不相同,则set一波。约束相同,现在还不是立刻判断矛盾。除非之前a和b在两个不同的集合里,此时给出a和b相同,就矛盾了。所以要用set来记录。反之合并Union,与b不同的元素就是与a不同的元素,所以合并一下。

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 100000 + 10;
set<int>st[N];
int n,x,y,k,cnt,a[N],b[N],fa[N],ans[N];
void init(int l,int r){
	for(int i=l;i<=r;i++){
		fa[a[i]] = a[i],	fa[b[i]] = b[i];
		st[a[i]].clear(),	st[b[i]].clear();
	}
}
int find(int x){
	return x == fa[x] ? x : (fa[x] = find(fa[x]));
}
void Union(int fx,int fy){
	fa[fx] = fy;
	for(set<int>::iterator it=st[fx].begin();it!=st[fx].end();it++)	st[fy].insert(*it);
	for(set<int>::iterator it=st[fy].begin();it!=st[fy].end();it++)	st[fx].insert(*it);
}
int main(){
	while(~scanf("%d",&n)){
		cnt = 0;
		ans[0] = 0;
		for(int i=0;i<N;i++)	st[i].clear();
		for(int i=0;i<N;i++)	fa[i] = i;
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&a[i],&b[i],&k);
			int fx = find(a[i]),	fy = find(b[i]);
			if(fx == fy){   //如果两个数在一个集合
				if(!k){	
					ans[++cnt] = i;
					init(ans[cnt-1]+1,ans[cnt]);
				}
			}else{  //两个数之前不在一个集合
				if(k){  //约束条件相同 
					if(st[fx].count(fy) || st[fy].count(fx)){
						ans[++cnt] = i;
						init(ans[cnt-1]+1,ans[cnt]);
					}else	Union(fx,fy);
				}else	st[fx].insert(fy),	st[fy].insert(fx);
			}
		}
		printf("%d\n",cnt);
		for(int i=1;i<=cnt;i++)
			printf("%d\n",ans[i]-ans[i-1]);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值