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

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

被折叠的 条评论
为什么被折叠?



