poj 3657

非常考分析能力的一个题目。

       因为这个答案是满足单调性的,可以二分,转化成判定性问题之后。这么考虑,如果把所有的询问按照回答降序排列,然后每处理一个询问的时候,先看它的区间是否被完全覆盖,如果是,则矛盾,否则把它的区间覆盖。

       解释一下,每次覆盖的时候,意思就是这个位置不能放更小的值,如果有一次询问区间没有空白的位置,证明这个值没有办法放进去。所以矛盾。反之,我们每次都任意找一空白处放进一个值,肯定能构造出解。

       但是,这个题目还要求值是唯一的,所以要一次处理所以相同的值,求交集,如果交集为空,矛盾。否则,查看交集,覆盖并集。

       到这里还有问题,这个题目的范围很大,要离散化,离散化还有一个问题,离散化后的相邻的两个值可能离散化前不相邻,那么覆盖了这两个端点后其实没有覆盖这个区间。

所以离散化的时候要对这样的点中间空出一个值。

代码如下

 

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#define ls (t<<1)

#define rs (t<<1|1)

#define midt (tr[t].l+tr[t].r>>1)

using namespace std;

const int maxn=25000+9;

int n,q;

int N;

struct D

{

    int id,key;

    bool operator <(const struct D & xx) const

    {

        return key<xx.key;

    }

}a[maxn<<1];



struct Q

{

    int l,r,min;

    bool operator <(const struct Q &xx) const

    {

        return min>xx.min;

    }

}qry[maxn],now[maxn];



struct

{

    int l,r;

    bool data;

}tr[maxn<<4];



void maketree(int t,int l,int r)

{

    tr[t].l=l;

    tr[t].r=r;

    tr[t].data=0;

    if(l==r) return;

    int mid=midt;

    maketree(ls,l,mid);

    maketree(rs,mid+1,r);

}



void pushdown(int t)

{

    if(tr[t].data==1)

    {

        tr[ls].data=tr[rs].data=1;

    }

}



bool query(int t,int l,int r)

{

    if(l==tr[t].l&&r==tr[t].r)

    return tr[t].data;

    pushdown(t);

    int mid=midt;

    if(r<=mid) return query(ls,l,r);

    else if(mid+1<=l) return query(rs,l,r);

    else

    {

        bool fla=1;

        if(query(ls,l,mid)==0) fla=0;

        if(query(rs,mid+1,r)==0) fla=0;

        return fla;

    }

}



void modify(int t,int l,int r)

{

    if(l==tr[t].l&&r==tr[t].r)

    {

        tr[t].data=1;

        return ;

    }

    pushdown(t);

    int mid=midt;

    if(r<=mid) modify(ls,l,r);

    else if(mid+1<=l) modify(rs,l,r);

    else

    {

        modify(ls,l,mid);

        modify(rs,mid+1,r);

    }

    if(tr[ls].data&&tr[rs].data) tr[t].data=1;

    else tr[t].data=0;

}



bool chk(int ret)

{

//    cout<<ret<<endl;

    for(int i=1;i<=ret;i++)

    now[i]=qry[i];

    sort(now+1,now+ret+1);

    maketree(1,1,N);

    for(int i=1,j;i<=ret;i=j)

    {

        int l=now[i].l,r=now[i].r;

        j=i+1;

        while(j<=ret&&now[j].min==now[i].min)

        {

            if(l>now[j].r||now[j].l>r) return false;

            l=max(l,now[j].l);

            r=min(r,now[j].r);

            j++;

        }

        if(query(1,l,r)) return false;

        for(int k=i;k<j;k++)

        modify(1,now[k].l,now[k].r);

    }

    return true;

}



int main()

{

//    freopen("in.txt","r",stdin);

    while(scanf("%d %d",&n,&q)!=EOF)

//     scanf("%d %d",&n,&q);

    {

        N=q<<2;

        for(int i=1;i<=q;i++)

        {

            scanf("%d %d %d",&qry[i].l,&qry[i].r,&qry[i].min);

            if(qry[i].l>qry[i].r)

            swap(qry[i].l,qry[i].r);

            a[i*2].id=i*2;

            a[i*2].key=qry[i].l;

            a[i*2+1].id=i*2+1;

            a[i*2+1].key=qry[i].r;

        }

        sort(a+2,a+q+q+2);

        a[1].key=-1;

        int lon=0;

        for(int i=2;i<=q+q+1;i++)

        {

            if(a[i].key!=a[i-1].key)

            {

                lon++;

                if(a[i].key!=a[i-1].key+1)

                lon++;

            }

            if(a[i].id&1) qry[a[i].id/2].r=lon;

            else qry[a[i].id/2].l=lon;

        }

        int st=1,ed=q,mid;

        while(st<ed)

        {

//            printf("%d %d\n",st,ed);

            mid=st+ed>>1;

            if(chk(mid)) st=mid+1;

            else ed=mid;

        }

        if(st==q&&chk(st))

        printf("0\n");

        else

        printf("%d\n",st);

    }

    return 0;

}


 

 

你可能感兴趣的:(poj)