题目链接:http://poj.org/problem?id=3468
题目大意:有一个长为10000000的墙,有1 <= n <= 10000个市长候选人去张贴海报,每个人的海报长度不限。上面的海报会覆盖下面的海报,问你最后能看见哪些海报。
思路:这个用线段树add标记维护当前区间的海报就行了,然后就MLE了。两个40000000的数组开不下。于是就必须优化。因为候选人只有10000个,如果把长度离散化一下就可以了,因为会不会覆盖只与两张长度的大小关系有关,而并不用保存具体长度大小。
例如:一张海报是1 - 10000,另外一张是2-5000000,可以把长度离散为1-3, 2-4。把所有海报的端点的相对大小关系保存下来就可以了。
只有如果每张海报的端点都不同,也只需要2*n个节点就行了。
还有查找的时候,只有查找当前区间的add[i]!=0就可以了。说明这个区间最上面就是这张海报。
思考:离散化, 区间的查找。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include <iostream>
#include <stdio.h>
#include <set>
#define ll long long
using namespace std;
#define MAX_NODE 800005
#define MAX_ 200005
struct NODE
{
int l, r;
}node[MAX_NODE];
int add[MAX_NODE];
set<int> s;
void BT(int i, int l ,int r) //建树
{
node[i].l=l;
node[i].r=r;
if(l==r) //根节点
{
return;
}
BT((i<<1), l, (l+r)/2); //建左子树
BT((i<<1)+1, (l+r)/2+1, r);//建右子树
}
int m=0;
void upadd(int i)
{
if(add[i])
{
add[i<<1]=add[i]; //把左右子的add标记进行更新
add[(i<<1)+1]=add[i];
add[i]=0; //清零父节点的add标记
}
}
void UP(int i, int l, int r, int c)//更新
{
if(node[i].l==l&&node[i].r==r)//找到更新区间
{
add[i]=c; //更新add标记
return;
}
if(node[i].l==node[i].r) //叶子节点
{
add[i]=c;
return;
}
upadd(i); //把此本节点的add往下移动
int mid=(node[i].l+node[i].r)/2;//继续寻找区间
if(r<=mid) //全在左区间
{
UP(i<<1, l, r, c);
}
else if(l>mid) //全在右区间
{
UP((i<<1)+1, l, r, c);
}
else
{
UP(i<<1, l, mid, c);
UP((i<<1)+1, mid+1, r, c);
}
}
void FD(int i, int l, int r) //查找
{
if(add[i]!=0)
{
s.insert(add[i]);
return;
}
if(l==r)
{
return;
}
FD(i<<1, l, (l+r)/2);
FD((i<<1)+1, (l+r)/2+1, r);
}
//建树 BT(1, 1 ,n);节点1-n
//查询 FD(1, a, b);[a, b]的信息
//更新 UP(1, a, b, c);//把区间的add+=a
int c[20005], p=0;
int ls[20005];
void lsh()
{
sort(c, c+p);
int cnt=unique(c, c+p)-c;
for(int i=0;i<p;i++)
ls[i]=lower_bound(c, c+cnt, ls[i])-c+1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(add, 0, sizeof(add));
p=0;
s.clear();
int n;
scanf("%d",&n);
BT(1, 1, 200005);
for(int i=1;i<=n;i++)
{
int a, b;
scanf("%d%d",&a,&b);
ls[p]=a, c[p++]=a;
ls[p]=b, c[p++]=b;
}
lsh(); //离散化
for(int i=1;i<p;i+=2)
{
UP(1, ls[i-1], ls[i], i); //更新
}
FD(1, 1, 200005);
printf("%d\n",s.size());
}
return 0;
}