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;
}