poj 2528 线段树+离散化+有颜色的区间覆盖

本文介绍了一种处理区间覆盖问题的方法,其中每个覆盖的区间带有颜色标识,并通过懒标记技术实现颜色向下传递,最终输出可见的颜色个数。

    区间覆盖,和一般的区间覆盖问题的区别是每个覆盖的区间是有颜色的,最后要输出可见的颜色个数。对于每个区间操作,我们可以采用懒标记的思想,等到有其他区间覆盖过来时,将该区间的颜色向下传递。具体见代码。

#include <cstdio>
#include <algorithm>
#include <iostream>

using namespace std;

struct node
{
    int l,r;
};
node a[10002];

int n,m,q;
int lisan[20002],f[80002];

void build(int l,int r,int k)
{
    q=max(q,k);
    f[k]=-2;                                        //f[k]=-2表示k结点所在的区间还没有被覆盖
    if (l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,2*k);
    build(mid+1,r,2*k+1);
}

void push(int k)
{
    if (f[k]>-1)
    {
        f[2*k]=f[2*k+1]=f[k];
    }
}

void change(int l,int r,int k,int L,int R,int VAL)
{
    if ((L<=l)&&(r<=R))
    {
        f[k]=VAL;                                    //直接用该点的颜色覆盖所在区间
        return;
    }
    push(k);                                        //将颜色向下传递
    int mid=(l+r)>>1;
    if (R<=mid) change(l,mid,2*k,L,R,VAL);
    else if (L>mid) change(mid+1,r,2*k+1,L,R,VAL);
    else
    {
        change(l,mid,2*k,L,mid,VAL);
        change(mid+1,r,2*k+1,mid+1,R,VAL);
    }
    if ((f[2*k]==-1)||(f[2*k+1]==-1)) f[k]=-1;        //f[k]=-1表示该区间有多种颜色
    else if (f[2*k]==-2) f[k]=f[2*k+1];
    else if (f[2*k+1]==-2) f[k]=f[2*k];
    else if (f[2*k]==f[2*k+1]) f[k]=f[2*k];
    else f[k]=-1;
}

bool work(int l,int r,int k,int L,int R,int VAL)
{
    if ((f[k]!=-1)&&(f[k]!=VAL)) return 0;
    if (f[k]==VAL) return 1;                               //找到该颜色
    int mid=(l+r)>>1;
    if (R<=mid) return work(l,mid,2*k,L,R,VAL);
    else if (L>mid) return work(mid+1,r,2*k+1,L,R,VAL);
    else
    {
        int t=work(l,mid,2*k,L,mid,VAL);
        if (t) return t;
        else return work(mid+1,r,2*k+1,mid+1,R,VAL);
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        q=0;
        scanf("%d",&n);
        m=0;
        for (int i=0;i<n;i++)
        {
            scanf("%d%d",&a[i].l,&a[i].r);
            lisan[m++]=a[i].l;
            lisan[m++]=a[i].r;
        }
        sort(lisan,lisan+m);
        m=unique(lisan,lisan+m)-lisan;
        build(0,m-1,1);
        for (int i=0;i<n;i++)
        {
            int l=lower_bound(lisan,lisan+m,a[i].l)-lisan;
            int r=lower_bound(lisan,lisan+m,a[i].r)-lisan;
            change(0,m-1,1,l,r,i);
        }
        int ans=0;
        for (int i=0;i<n;i++)
        {
            int l=lower_bound(lisan,lisan+m,a[i].l)-lisan;
            int r=lower_bound(lisan,lisan+m,a[i].r)-lisan;
            ans+=work(0,m-1,1,l,r,i);
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值