ssl 2785 询问 并查集+二分

来源:互联网 发布:ubuntu网络配置命令 编辑:程序博客网 时间:2024/06/09 19:31

题目大意

A为未知的一个元素两两不相同的序列
现在给定一些区间和这个区间的最小值(不一定对)
问那个区间是最先与之前的区间冲突的

分析

一开始想写一些奇怪的线段树,然后发现自己并不会写。。。
于是就想了想如何判断几个区间是否合法,发现:

最小值相同的区间放在一起,求出他们的交集及并集,如果区间交为空说明序列中有重复数字,不合法。如果一个最小值为a1的并集被a2的交集覆盖了,且a1<a2,则答案不合法。这个可以用并查集弄弄:于是 i 在并查集中的根就是 i 所在的最长连续覆盖区间的右端点 +1,也就是说 后面第一个没被覆盖的位置。 覆盖 [l, r] 时就从 l 开始,每次找到下一个没被覆盖的位置,如果还没超过 r, 就把他覆盖然后合并。  

ps:并查集用while,不然会暴栈,对c++深深的恶意。。。

code

#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<string>#include<algorithm>using namespace std;int f[1500000];struct arr{    int l,r,w;}a[30000],b[30000];struct arr1{    int l,r;    int L,R;}c[30000];int n,m;bool cmp(arr a,arr b){    return a.w>b.w;}int find(int x){    int y=x;    while (f[x]!=x)    {        x=f[x];    }     int z=0;    while (f[y]!=y)    {        z=y;        y=f[y];        f[z]=x;    }    return x;}int check(int mid){    memset(b,0,sizeof(b));    memset(c,0,sizeof(c));    for (int i=1;i<=mid;i++)        b[i]=a[i];    sort(b+1,b+1+mid,cmp);    int nn=0;    for (int i=1;i<=mid;i++)        if (b[i-1].w!=b[i].w)        {            nn++;            c[nn].l=c[nn].L=b[i].l;            c[nn].r=c[nn].R=b[i].r;        }        else        {            c[nn].l=min(c[nn].l,b[i].l);            c[nn].r=max(c[nn].r,b[i].r);            c[nn].L=max(c[nn].L,b[i].l);            c[nn].R=min(c[nn].R,b[i].r);            if (c[nn].R<c[nn].L) return 1;        }    for (int i=1;i<=n+1;i++)        f[i]=i;    for (int i=1;i<=nn;i++)    {        int x=c[i].L,y=c[i].R+1;        if (find(x)==find(y))             return 1;        x=c[i].l,y=c[i].r+1;        while (find(x)<y)         {            x=f[x];            f[x]++;            x++;        }    }    return 0;}int main(){    //freopen("bales.in","r",stdin);    //freopen("bales.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++)    {        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);    }    int l=0,r=m;    while (l<r)    {        int mid=(l+r+1)/2;        if (check(mid))            r=mid-1;        else            l=mid;    }    if (!check(m)) l=-1;    printf("%d",l+1);}