题目链接:http://poj.org/problem?id=2528
题意:有N张海报,每张海报贴在[L,R]的区间上,问最后还能看见多少张海报
思路:一开始在纠结如何保存一个区间有多少张海报,上一次填色的题目因为数据少,可以用二进制保存,这次数据非常大,不过因为只查询一次,直接遍历一次线段树就可以了,不过需要离散化,注意离散化的时候之间隔了1个数以上的2个数离散化时也要隔一个数,不然会出错(数组要开10倍RE了……开20倍就过了)
比如 :1 7 1 4
1 2 -> 1 2
4 7 3 4
这样离散明显不对的,正确的是:
1 7 1 5
1 2 -> 1 2
4 7 4 5
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 10030
using namespace std;
struct Tree
{
int l,r,date;
}tree[maxn*20];
int lazy[maxn*20],post[maxn*20][2],temp[maxn*20],vis2[maxn*20],vis[maxn*1000],res;
void build(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
if (l==r) return;
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
}
void update(int root,int l,int r,int val)
{
if (tree[root].l>=l && tree[root].r<=r)
{
lazy[root]=val;
return;
}
if (lazy[root]!=0)
{
lazy[root<<1]=lazy[root];
lazy[root<<1|1]=lazy[root];
lazy[root]=0;
}
int mid=(tree[root].l+tree[root].r)>>1;//
if (l<=mid) update(root<<1,l,r,val);
if (r>mid) update(root<<1|1,l,r,val);
}
void que(int root)
{
if (lazy[root]!=0)
{
if (vis2[lazy[root]]==0)
{
res++;
vis2[lazy[root]]=1;
}
return;
}
if (tree[root].l==tree[root].r) return;
que(root<<1);
que(root<<1|1);
}
int main()
{
int t,n;
scanf("%d",&t);
while (t--)
{
scanf("%d",&n);
int cnt=0;
memset(vis,0,sizeof(vis));
memset(vis2,0,sizeof(vis2));
memset(lazy,0,sizeof(lazy));
for (int i=0;i<n;i++)
{
scanf("%d%d",&post[i][0],&post[i][1]);
if (!vis[post[i][0]])
{
temp[cnt++]=post[i][0];
vis[post[i][0]]=1;
}
if (!vis[post[i][1]])
{
temp[cnt++]=post[i][1];
vis[post[i][1]]=1;
}
}
sort(temp,temp+cnt);
int map=0;
for (int i=0;i<cnt;i++)
{
vis[temp[i]]=++map;
if (temp[i+1]-temp[i]>1) map++;
}
build(1,1,vis[temp[cnt-1]]);
for (int i=0;i<n;i++)
{
int a=vis[post[i][0]],b=vis[post[i][1]];
update(1,a,b,i+1);
}
res=0;
que(1);
cout<<res<<endl;
}
}