【队内胡策 11.1】 T3

来源:互联网 发布:nba2016数据 编辑:程序博客网 时间:2024/05/19 16:33

这里写图片描述
这里写图片描述

考试的时候打了八十分暴力QAQ虽然八十分过了,但是算法有bug。。数据没有卡我算法,然后就水过了8个点。。害怕。
正解:
二分+并查集
二分前mid个是否有矛盾的,特判一下全部符合的,答案为n+1
验证答案时,用并查集维护。
首先,如果已知一段区间[a,b]的最小值为x1,再出现一组猜测:[c,d]的最小值为x2。
① 若x1 > x2且区间[c,d] 包含在[a,b]里,则自相矛盾。
② 若x1==x2且区间[c,d]和[a,b]没有交集,则自相矛盾。
③ 若x1 < x2且区间[a,b] 包含在[c,d]里,则自相矛盾。
为了简化问题,可以把每一组猜测按照数字大小排序,这样就可以只处理其中的两种情况。
假设现在按照从大到小排序,从头到尾枚举:
如果遇见①②两种情况,则自相矛盾
记录目前可以确定的最小值为某个数的最大区间和最小区间。维护四个变量:lmin,lmax,rmin,rmax
对于最大的区间最小值为某一个数的区间[l,r],将它包含的所有的长度为1的区间的fa数组指向r+1(至于为什么不是指向r,等会再说)。
处理到与上一个数值相同的,就更新四个变量,每次更新如果发现不符合②,直接return false
若与上一个的数值不同,查看是否是①中的情况(当前集合的父亲是否大于rmin),如果不是,就把目前已知的区间最小值为上一个数字的最大的区间合并起来。
注:
指向r会有bug。如果指向r,则应该判断当前集合的父亲是否大于等于rmin,但是如果像这样的情况:最后一组是7 7 1,也就是左右端点相等,判断等于,就会返回false

具体看代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=1000000+10;int n,t,ans;int fa[maxn];struct hh{    int l,r,x;}e[maxn],a[maxn];bool cmp(hh x,hh y){    return x.x>y.x;}int find(int x){    if(fa[x]==x) return x;    return fa[x]=find(fa[x]);}bool check(int mid){    int lmin,lmax,rmin,rmax;    for(int i=1;i<=mid;++i) a[i]=e[i];    for(int i=1;i<=n+5;++i) fa[i]=i;    sort(a+1,a+mid+1,cmp);    for(int i=1;i<=mid+1;++i)    {        if(i==1)        {            lmin=lmax=a[i].l;            rmin=rmax=a[i].r;        }        else if(i==mid+1)        {            if(find(lmax)>rmin) return false;            return true;        }        else if(a[i].x==a[i-1].x)        {            lmin=min(lmin,a[i].l);            lmax=max(lmax,a[i].l);            rmin=min(rmin,a[i].r);            rmax=max(rmax,a[i].r);            if(lmax>rmin) return false;        }        else        {            if(find(lmax)>rmin) return false;            for(int j=lmin;j<=rmax;++j)              fa[find(j)]=find(rmax+1);            lmin=lmax=a[i].l;            rmin=rmax=a[i].r;        }    }}int main(){    scanf("%d%d",&n,&t);    for(int i=1;i<=t;++i) scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].x);    int l=0,r=t+1;    while(r-l>1)    {        int mid=(l+r)>>1;        if(check(mid)) l=mid;        else ans=r=mid;    }    if(l==t&&check(t)) ans=t+1;    printf("%d",ans);    return 0;}
原创粉丝点击