1. 程式人生 > >POJ--2528 Mayor's posters (線段樹)

POJ--2528 Mayor's posters (線段樹)

題目連結:POJ--2528 Mayor's posters

題目大意:給你一個無限長的板子,然後依次往上面貼n張等高的海報,問你最後能看到多少張海報。

思路分析:線段樹區間更新問題,但是要注意,給的長度的可能非常大,有1e9,不加處理直接維護一個線段樹肯定會

MLE,TLE,但是我們注意到一共最多隻有2e4個點,因此我們可以用離散化的思想先對區間進行預處理,所謂的離散化,

在我理解看來就是將一個很大的區間對映為一個很小的區間,而不改變原有的大小覆蓋關係,但是注意簡單的離散化可能

會出現錯誤,給出下面兩個簡單的例子應該能體現普通離散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通離散化後都變成了[1,4][1,2][3,4]
線段2覆蓋了[1,2],線段3覆蓋了[3,4],那麼線段1是否被完全覆蓋掉了呢?
例子一是完全被覆蓋掉了,而例子二沒有被覆蓋

解決的辦法則是對於距離大於1的兩相鄰點,中間再插入一個點,本題還用到了Lazy標記的思想

直接更新區間進行標記而先不對子節點進行處理,如果需要往下更新再將標記下傳一層。

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 100010
#define LL long long
int a[maxn*4],ll[maxn],rr[maxn],lz[maxn*4
]; bool fa[maxn*4]; vector<int>q; int ans; void init(){ memset(a,-1,sizeof(a)); memset(ll,0,sizeof(ll)); memset(rr,0,sizeof(rr)); memset(fa,0,sizeof(fa)); q.clear();ans=0; } int getid(int x){ return lower_bound(q.begin(),q.end(),x)-q.begin()+1; } void lazy(int in){ if
(a[in]>0){ a[in*2]=a[in]; a[in*2+1]=a[in]; a[in]=-1; } } void updata(int l,int r,int x,int y,int in,int va){ if(l==x&&r==y){ a[in]=va; return ; } lazy(in); int mid=(l+r)/2; if(y<=mid){ updata(l,mid,x,y,in*2,va); }else if(x>mid){ updata(mid+1,r,x,y,in*2+1,va); }else{ updata(l,mid,x,mid,in*2,va); updata(mid+1,r,mid+1,y,in*2+1,va); } } void query(int l,int r,int in){ //cout<<a[in]<<endl; if(a[in]>0){ if(!fa[a[in]]){ fa[a[in]]=1; ans++; } return ; } if(l==r) return ; int mid=(l+r)/2; query(l,mid,in*2); query(mid+1,r,in*2+1); } int main(){ int t; cin>>t; while(t--){ init(); int n,mx=0; cin>>n; for(int j=1;j<=m;j++){ cin>>ll[j]>>rr[j]; q.push_back(ll[j]); q.push_back(rr[j]); } sort(q.begin(),q.end()); q.erase(unique(q.begin(),q.end()),q.end()); int z=q.size(); for(int j=1;j<z;j++){ if(q[j]-q[j-1]>1){ q.push_back(q[j-1]+1); } } sort(q.begin(),q.end()); mx=q.size(); for(int j=1;j<=m;j++){ int l=getid(ll[j]); int r=getid(rr[j]); updata(1,mx,l,r,1,j); } query(1,mx,1); cout<<ans<<endl; } }