hdu 6109 数据分割(并查集,倍增)

题意:比较绕,n个表达式,表示a==b或者a!=b,有矛盾就重新开始,问可以分成多少段,每段多大。。

 

思路:倍增,On判断,也可以并查集加set维护(合并要注意使得集合头要是最早出现的。。),这里提供一下倍增的做法

PS。顺便吐槽一下百度之星的测评姬。。。还想吐槽一下自己比去年大概还弱,,今年怕是要打铁了

代码:

 

#include<bits/stdc++.h>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof(a))
#define bug puts("bug");
#define PB push_back
#define MP make_pair
#define X first
#define Y second
typedef unsigned long long ll;
typedef pair<int,int> pii;
const int maxn=1e6+10;
using namespace std;
int n,a[maxn],b[maxn],c[maxn];
int f[maxn];
int fin(int x){
    if(x==f[x]) return x;
    return f[x]=fin(f[x]);
}
int un(int x,int y){
    int fx=fin(x),fy=fin(y);
    if(fx!=fy) f[fx]=fy;
}
int ok(int l,int r){
    if(r>=n) return 0;
    int ret=1;
    for(int i=l;i<=r;i++) if(c[i]==1) un(a[i],b[i]);
    for(int i=l;i<=r;i++) if(c[i]==0&&fin(a[i])==fin(b[i])) ret=0;
    for(int i=l;i<=r;i++) f[a[i]]=a[i],f[b[i]]=b[i];
    return ret;
}

int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
        for(int i=0;i<n+10;i++) f[i]=i;
        int l=0;
        vector<int> ans;
        while(l<n){
            int d=1;
            int ll=l;
            while(ok(l,ll+d)){
               while(ok(l,ll+d*2)) d*=2;
               ll+=d;
               d=1;
            }
            if(ll+d<n)ans.PB(ll+d-l+1);
            l=ll+d+1;
        }
        printf("%d\n",ans.size());
        for(int i=0;i<ans.size();i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}



 

posted @ 2017-08-12 21:16  zhangxianlong  阅读(97)  评论(0编辑  收藏  举报