题目大意:在一块儿宣传栏中贴宣传单,规定宽度相同,长度不同。按一定顺序贴,给出宣传单的起始和结束位置,这里位置不能忽略成点(而是一段长度),问最后会看到几个宣传单。
解题思路:由于给出的数据范围多大,所以要先进行离散化减少复杂度,因为这里给出的不是”点“是带长度的,所以一般的离散化会出现离散失真,这里可以在离散的时候增加技巧,即在不相邻的数据里增加分隔点,凸显不连续。然后进行线段树成段替换,最后求出整个区间的不同宣传单个数。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define mid (L+R)/2 #define lson rt*2,L,mid #define rson rt*2+1,mid+1,R const int maxn=50000; int lm[maxn/2],rm[maxn/2]; int col[maxn*4]; int Hash[maxn]; int A[maxn]; int num=0; int discretization(int l,int r,int key){ //离散化 while(l<=r){ int m=(l+r)/2; if(key==A[m]){ return m; }else if(key<A[m]){ r=m-1; }else{ l=m+1; } } } void PushDown(int rt){ if(col[rt]!=-1){ col[rt*2]=col[rt]; col[rt*2+1]=col[rt]; col[rt]=-1; } } void update(int rt,int L,int R,int l_ran,int r_ran,int _col){ if(l_ran<=L&&R<=r_ran){ col[rt]=_col; return ; } PushDown(rt); if(l_ran<=mid) update(lson,l_ran,r_ran,_col); if(r_ran>mid) update(rson,l_ran,r_ran,_col); } void query(int rt,int L,int R){ if(col[rt]!=-1){ if(!Hash[col[rt]]){ num++; Hash[col[rt]]=1; } return ; } if(L==R) return ; query(lson); query(rson); } void debug(){ for(int i=1;i<32;i++){ printf("%d %d ",i,col[i]); } } int main(){ int t; scanf("%d",&t); while(t--){ int n,nn=0,m; scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d%d",&lm[i],&rm[i]); A[nn++]=lm[i]; A[nn++]=rm[i]; } sort(A,A+nn); m=1; for(int i=0;i<nn-1;i++){ //去重 if(A[i]!=A[i+1]){ A[m++]=A[i+1]; } } for(int i=m-1;i>0;i--){ //添加分隔点 if(A[i]!=A[i-1]+1){ A[m++]=A[i-1]+1; } } sort(A,A+m); int tml,tmr; memset(col,-1,sizeof(col)); for(int i=0;i<n;i++){ tml= discretization(0,m-1,lm[i]); //离散化 tmr= discretization(0,m-1,rm[i]); //离散化 update(1,0,m-1,tml,tmr,i); } // debug(); memset(Hash,0,sizeof(Hash)); num=0; query(1,0,m-1); printf("%d ",num); } return 0; }