题目链接
http://poj.org/problem?id=2528
题目
n(n<=10000) 个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000) 。求出最后还能看见多少张海报。
Input
第一行: 样例个数T
第二行: 贴海报的人n
第三行: 每个人贴海报的范围
接下来n行: 每个人贴海报的范围
Output
对于每一个输入,输出最后可以看到的海报张数。
Sample Input
1
5
1 4
2 6
8 10
3 4
7 10
Sample Output
4
分析
数据范围有1e7,需要对数据进行离散化。
离散过程:
排序、相邻数相差大于1在其中插入一个值、用下标代替值。比一般的离散化多了一个插入值的步骤,这是因为如果相邻数之差大于1,表示其中有空位,离散化后变成连续的数,表示没有空位,含义上有所改变。故要插入一个中间值,使含义不变。
一开始用map去实现离散化,超时了,很迷。参考网上博客用二分去写,79msA了,orz。
此题的线段树不用维护结点信息,因为延迟标记就代表了结点信息。故不需要up操作去回溯更新父结点。统计结果时暴力统计叶子结点的颜色情况即可,将延迟标记传递到每个叶子结点,保证叶子结点的正确性。
AC代码
//79ms 2.7MB
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#define lson p<<1
#define rson p<<1|1
using namespace std;
const int maxn=2e5+100;
struct node
{
int l,r;//结点所维护的区间
int mark;//延迟标记
}T[maxn<<2];//线段树要开四倍空间
int x[maxn],y[maxn],a[maxn];
int vis[maxn];//叶子染色的颜色
//map<int,int> mp;//map超时?
void down(int p)
{
if(!T[p].mark) return ;
T[lson].mark=T[rson].mark=T[p].mark;
T[p].mark=0;
}
void build(int p,int l,int r)//p表示结点编号,l、r表示结点p所表示的区间
{
T[p].mark=0;
T[p].l=l,T[p].r=r;//确定结点p所表示的区间[l,r]
if(l==r) //确定叶子结点所表示的信息
{
return ;
}
int mid=(l+r)>>1;
build(lson,l,mid); //递归创建左子树
build(rson,mid+1,r); //递归创建右子树
}
void update(int p,int x,int y,int v)
{
if(T[p].l==x && T[p].r==y) //区间恰好重合
{
T[p].mark=v; //标记信息修改到此结点打止
return ;
}
//区间在p的子树结点中,要调用子树结点信息,必须先下传延迟标记
down(p); //下传标记将p的左右子结点修改,只修改了这两个结点,延迟标记放在了这两个结点上
int mid=(T[p].l+T[p].r)>>1;
if(y<=mid) //区间[x,y]一定在左子树上
update(lson,x,y,v);
else if(x>mid) //区间[x,y]一定在右子树上
update(rson,x,y,v);
else
{
//必须将区间分成两份小区间[x,mid]和[mid+1,y]
update(lson,x,mid,v);
update(rson,mid+1,y,v);
}
}
void query(int p)
{
if(T[p].l==T[p].r)
{
vis[T[p].mark]=1;
return ;
}
down(p);
query(lson);
query(rson);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
//mp.clear();
int m,tot=0,n=0;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
a[tot++]=x[i];
a[tot++]=y[i];
}
sort(a,a+tot);
tot=unique(a,a+tot)-a;
int t=tot;
for(int i=1;i<t;i++)
if(a[i]-a[i-1]>1)
a[tot++]=a[i-1]+1;
sort(a,a+tot);
build(1,1,tot);
for(int i=1;i<=m;i++)
{
int l=lower_bound(a,a+tot,x[i])-a+1;
int r=lower_bound(a,a+tot,y[i])-a+1;
//cout<<l<<" "<<r<<endl;
update(1,l,r,i);
}
query(1);//将延迟标记传递到每个叶子结点
int ans=0;
for(int i=1;i<=m;i++)
if(vis[i]) ans++;
printf("%d\n",ans);
}
return 0;
}