题目链接:
http://poj.org/problem?id=2528
题意:
n 个人依次贴海报,给出每张海报所贴的范围 li ,ri 求出最后还能看见多少张海报。
题解:
线段树,因为后来的海报总会覆盖之前张贴的海报,那么我们把操作从后往前枚举,用线段树 tr [ i ] . val 表示标号为 i 的节点所代表的区间中已经有多少个位置被覆盖。
然后就是简单的区间查询和区间修改。
然后看它的数据范围 10000000 直接线段树妥妥的MLE,需要用离散化,而且这个离散化还要注意一个细节,简单的排序后编号是不可以的,举一个例子:
3
1 10
1 4
6 10
直接排序后标号为
vis[1]=1;vis[4]=2;vis[6]=3;vis[10]=4;
然后照这样的做法,先覆盖 3~4 在覆盖 1~2 ,然后覆盖 1~4 ,答案是 2 ,然而正确答案是 3 ,中间的位置5被神奇的跳过了,新的离散方法就是,离散时若发现 a[i] - a[i-1] > 1 那么 vis [ a[i] ] = vis [ a[i-1] ] + 2 ,这样的话就相当于给中间那些数留出来了一个空位,防止上面的情况发生,具体细节看代码。
代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<map>
#define lson (id*2)
#define rson (id*2+1)
using namespace std;
int ans;
struct node{
int val;
int lazy;
}tr[160005];
void pushup(int id)
{
tr[id].val=tr[lson].val+tr[rson].val;
}
void pushdown(int id,int l,int r)
{
if (tr[id].lazy)
{
int mid=(l+r)/2;
tr[lson].val=mid-l+1;tr[lson].lazy=1;
tr[rson].val=r-mid;tr[rson].lazy=1;
tr[id].lazy=0;
}
}
void build(int id,int l,int r)
{
tr[id].lazy=0;
if (l>=r) {tr[id].val=0;return ;}
int mid=(l+r)/2;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(id);
return ;
}
void add(int id,int l,int r,int L,int R,int v)
{
if (l>r || L>r || R<l) return ;
if (l>=L && r<=R) {tr[id].val=r-l+1;tr[id].lazy=1;return ;}
int mid=(l+r)/2;
pushdown(id,l,r);
if (L<=mid) add(lson,l,mid,L,R,v);
if (R>=mid+1) add(rson,mid+1,r,L,R,v);
pushup(id);
}
void query(int id,int l,int r,int L,int R)
{
if (l>r || L>r || R<l) return ;
if (l>=L && r<=R) {ans+=tr[id].val;return ;}
int mid=(l+r)/2;
pushdown(id,l,r);
if (L<=mid) query(lson,l,mid,L,R);
if (R>=mid+1) query(rson,mid+1,r,L,R);
pushup(id);
}
int zans,len,tot,T,n,m,l[10005],r[10005],a[20005];
map<int,int>vis;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
tot=0;len=0;zans=0;
// vis.clear();
for (int i=1;i<=n;i++)
{
scanf("%d%d",&l[i],&r[i]);
tot++;a[tot]=l[i];
tot++;a[tot]=r[i];
if (l[i]>r[i]) swap(l[i],r[i]);
}
sort(a+1,a+1+tot);
vis[a[1]]=1;
len=1;
for (int i=2;i<=tot;i++)
if (a[i]==a[i-1]) continue;
else if (a[i]-a[i-1]>1)
len+=2,vis[a[i]]=len;
else len++,vis[a[i]]=len;
//cout<<tr[1].val<<endl;
build(1,1,len);
// for (int i=1;i<=len*4;i++)
/// tr[i].val=0,tr[i].lazy=0;
//cout<<tr[1].val<<endl;
for (int i=n;i>=1;i--)
{
ans=0;query(1,1,len,vis[l[i]],vis[r[i]]);
if (ans!=vis[r[i]]-vis[l[i]]+1)
zans++,add(1,1,len,vis[l[i]],vis[r[i]],1);
if (tr[1].val==len) break;
}
printf("%d\n",zans);
}
}