题意:
为了竞选市长,竞选者在一墙上同一高度进行贴海报为自己拉票。海报覆盖一块连续的区域,后来贴的可以覆盖前面贴的,问到最后一共可以看多多少张海报。
整块墙可以看做是一个水平数轴,每张海报就是数轴上的一个区间。
题解:
数据规模为千万级别的,直接建立线段树,内存时间都会超。
需要对这些大点的数据进行离散化:缩小数据规模,但是保持各个海报的相对顺序和覆盖关系。
举个栗子:
对于区间[1,1000],[500,2000],[1500,2500].那么把所有区间端点1,500,1000,1500,2000,2500离散化后就是1,2,3,4,5,6.离散化后所得区间为:[1,3],[2,5],[4,6].
然后对离散化后的区间进行统计。这个时候发现[2,5]被覆盖了,也就是我们查询的时候是整数进行查询的,世纪上3和4之间是能看到海报的。所以这种之间排序后的离散化是行不通的。
上述离散的根本所在是:原先1000和1500并不相邻,离散后相邻。所以我们离散的时候要保证原先不相邻的继续不相邻。
好吧,以上我一开始看别人的题解,我还真信了!!!
然而,事实是:第一种简单的离散是可以行的通的,why?刚才一大堆分析只是表面现象,仔细想一下,先贴[1,3],再贴[2,5]这个时候,点1属于第一个人的,点2属于第二个人的(也就是第二个人并没有没覆盖),然后贴[4,6],点4属于第三个了。没毛病!这点要理解清楚。问题的根本在于线段树query的时候是离散的!
不过这种离散思想的分析是很好的,我把保证不相邻离散的代码注释掉了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<vector>
#include<functional>
#include<utility>
#include<set>
#include<map>
#include<cmath>
#include<cctype>
#define INF 0x3f3f3f3fusing namespace std;const int maxn=10000+10;
#define lson 2*i,l,m
#define rson 2*i+1,m+1,rbool vis[maxn];
struct node
{int l,r;
}nodes[maxn];int x[maxn<<2];//4倍线段的数量,一个线段两个节点+离散化
int col[maxn<<4];int ans;void pushdown(int i)
{if(col[i]!=-1){col[2*i]=col[2*i+1]=col[i];col[i]=-1;}
}void update(int ql,int qr, int v,int i,int l,int r)
{if(ql<=l&&qr>=r){col[i]=v;return;}pushdown(i);int m=(r+l)/2;if(ql<=m)update(ql,qr,v,lson);if(qr>m)update(ql,qr,v,rson);
}void query(int i,int l,int r)
{if(col[i]!=-1){if(!vis[col[i]]){ans++;vis[col[i]]=true;}return;}if(l==r)return;int m=(l+r)/2;query(lson);query(rson);
}int main()
{int t;cin>>t;while(t--){int n;cin>>n;int sz=0;for(int i=0;i<n;i++){scanf("%d%d",&nodes[i].l,&nodes[i].r);x[sz++]=nodes[i].l;x[sz++]=nodes[i].r;}sort(x,x+sz);int m=1;//去重for(int i=1;i<sz;i++)if(x[i]!=x[i-1])x[m++]=x[i];//离散化/* for(int i=m-1;i>0;i--)if(x[i]!=x[i-1]+1)x[m++]=x[i-1]+1;//使得原先不相邻的继续不相邻*/sort(x,x+m);memset(col,-1,sizeof(col));for(int i=0;i<n;i++){int l=lower_bound(x,x+m,nodes[i].l)-x+1;//离散化int r=lower_bound(x,x+m,nodes[i].r)-x+1;//离散化update(l,r,i,1,1,m);}ans=0;memset(vis,false,sizeof(vis));query(1,1,m);cout<<ans<<endl;}}