Mayor's posters (POJ 2528)线段树+离散化

n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri (1<=li<=ri<=1e7) 。求出最后还能看见多少张海报。
Input
第一行: 样例个数T
第二行: 贴海报的人n
第三行: 每个人贴海报的范围
接下来n行: 每个人贴海报的范围
Output
对于每一个输入,输出最后可以看到的海报张数。下面这个图是样例解释
在这里插入图片描述
Sample Input
1
5
1 4
2 6
8 10
3 4
7 10
Sample Output
4

海报张贴的范围是1e7直接线段树是肯定要超时的更别说还多个样例了,但是海报的张数才1e4,所以总的范围内有非常多点是没有用到的,可以把这些点全部省略只保留用到的端点,然后在线段树就方便许多了,然后还有一个问题
先来个样例吧
2
1 5
1 2
4 5
正确答案应该是3,但是直离散化端点后之后求得的是2,在点2和4之间应该还有一段但是离散化端点之后这一段就被省略了,所以我们需要把省略的这一把分再加入离散化里面,只用加一个省略线段之间的任意一点就可以了(如果省略部分长度大于1),这样就能ac啦,这道题数据有点水,不加省略的部分也能ac。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std; 
typedef long long ll;
const int N=1e4+10;
int n,t,a[N],l[N],r[N],idx;
vector<int> ve;
struct node
{
	int l,r;
	int id;//表示将整个区间覆盖的报纸编号,0表示不存在完全覆盖
}tr[N<<4];
void pushdown(int rt)//只保存能完全覆盖的最小区间,就不用pushup了
{
	if(tr[rt].id)
	{
		tr[rt<<1|1].id=tr[rt<<1].id=tr[rt].id;
		tr[rt].id=0;//记得清空
	}
}
void build(int rt,int l,int r)
{
	if(l==r) tr[rt]={l,l,0};
	else 
	{
		tr[rt]={l,r};
		int mid=l+r>>1;
		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);
	}
}
void updata(int rt,int l,int r,int d)
{
	if(l<=tr[rt].l&&tr[rt].r<=r)
	{
		tr[rt].id=d;
	}
	else 
	{
		pushdown(rt);
		int mid =tr[rt].l+tr[rt].r>>1;
		if(l<=mid) updata(rt<<1,l,r,d);
		if(r>mid) updata(rt<<1|1,l,r,d);
	}
}
int ans;
bool st[N];
void query(int rt,int l,int r)
{
	if(tr[rt].id)
	{
		if(!st[tr[rt].id])
		{
	  		ans++;
	  		st[tr[rt].id]=1;
	  	}
	  	return ;
	}
	if(tr[rt].l==tr[rt].r) return ;//记得及时结束
	pushdown(rt);
	int mid=tr[rt].l+tr[rt].r>>1;
	if(l<=mid) query(rt<<1,l,r);
	if(r>mid) query(rt<<1|1,l,r);
}
int main()
{
	
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		ve.clear();
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d",l+i,r+i);
			ve.push_back(l[i]);
			ve.push_back(r[i]);
		}
		sort(ve.begin(),ve.end());
		ve.erase(unique(ve.begin(),ve.end()),ve.end());//去重
		int sz=ve.size();//一定要加这一步,因为后面遍历的途中ve.size()就在变化,会一直向里面再加多余的点直到MLE
		for(int i=1;i<sz;i++)
			if(ve[i]-ve[i-1]>1) ve.push_back((ve[i]-1));
		sort(ve.begin(),ve.end());
		build(1,1,ve.size());
		for(int i=1;i<=n;i++)
		{
			int x=lower_bound(ve.begin(),ve.end(),l[i])-ve.begin()+1;//我想要端点从1开始
			int y=lower_bound(ve.begin(),ve.end(),r[i])-ve.begin()+1;
			updata(1,x,y,i);
		}
		ans=0;
		memset(st,0,sizeof st);
		query(1,1,ve.size());
		printf("%d
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/neflibata/p/12871751.html