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\n",ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章