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
",st,ed);
            mid=st+ed>>1;
            if(chk(mid)) st=mid+1;
            else ed=mid;
        }
        if(st==q&&chk(st))
        printf("0
");
        else
        printf("%d
",st);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/bbsno1/p/3253786.html