/*线段树+离散化
题意:在长度1~10000000的墙上贴海报,可以覆盖前一张,按输入顺序在墙上贴海报,求最后能看到几张海报。
思路:更新线段树,在左右值相同的线段区间更新为贴满,f值记录被哪张海报贴满。
寻找区间的过程,若某父区间早被贴满,则先更新他的子区间,然后该父区间f记为0,表示不被一张海报贴满。
区间很大,先对区间进行离散化处理。
*/
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 10000000
#define maxn 20005
int f[maxn];
int s[maxn];
bool visit[maxn];
int fn;
//int ff[maxn];
int post[maxn][2];
struct node
{
int f;
int l,r;
int lv,rv;
}tree[N*5];
void build(int l,int r,int root)//建区间树
{
tree[root].l=l;
tree[root].r=r;
tree[root].lv=f[l];
tree[root].rv=f[r];
tree[root].f=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,root*2);
build(mid+1,r,root*2+1);
}
void update(int lv,int rv,int n,int root)//更新线段树,即新张贴一张海报
{
if(lv>rv) return ;
if(tree[root].lv==lv&&tree[root].rv==rv){//表示被第n张海报贴满
tree[root].f=n;
return;
}
int mid=(tree[root].l+tree[root].r)>>1;
int midv=f[mid];
if(tree[root].f){//当前区间不是要贴海报的区间,若之前该区间被第n张贴满,则要先更新其子区间
int k=tree[root].f;
update(tree[root].lv,f[mid],k,root*2);
update(f[mid+1],tree[root].rv,k,root*2+1);
tree[root].f=0;
}
if(midv>=rv) update(lv,rv,n,root*2);
else if(midv<lv) update(lv,rv,n,root*2+1);
else {
update(lv,midv,n,root*2);
update(f[mid+1],rv,n,root*2+1);
}
}
int query(int root)//统计被贴满的区间,且不重复计数
{
if(tree[root].f){
if(!visit[tree[root].f]){
visit[tree[root].f]=true;
return 1;
}
return 0;
}
if(tree[root].l==tree[root].r) return 0;
return query(root*2)+query(root*2+1);
}
int main()
{
int n,t;
int x,y;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d %d",&post[i][0],&post[i][1]);
s[i*2]=post[i][0];
s[i*2+1]=post[i][1];
}
sort(s,s+n*2);
fn=0;
f[++fn]=s[0];
// ff[s[0]]=fn;
for(int i=1;i<2*n;i++)
if(s[i]==s[i-1]) continue;
else {
f[++fn]=s[i];//离散化区间
// ff[s[i]]=fn;
}
build(1,fn,1);
for(int i=0;i<n;i++)
update(post[i][0],post[i][1],i+1,1);//张贴下一张海报
memset(visit,false,sizeof(visit));
printf("%d\n",query(1));
}
return 0;
}
poj-2528(线段树+离散化)
最新推荐文章于 2020-03-10 14:07:43 发布