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; } }