Description
定义两个区间互相匹配表示这两个区间有交集。
给出长度为N的区间序列A,M次询问,每次询问序列A中最长的连续子序列,使得子序列中的每个区间都与[L,R]互相匹配
N<=50000,M<=200000
把区间看作平面上的点(l,r)(以下均称为点以便区分)
能匹配A[a..b]的询问点在一个四分之一平面l<=min(A[a..b].r),r>=max(A[a..b].l) 上,于是可以枚举所有长度不超过sqrt(n)的子串,对每种长度的子串可以排序后和询问一起统一处理
对于更大的区间不能这样暴力处理,那么从[1,n]开始向下分治到区间[l,r],大于sqrt(n)的答案可能跨过区间中点m或在m某侧,而跨过m的可以拆成[a..m][m+1..b]两段,枚举a,b的取值,可以发现每个a或b的取值恰好使一个四分之一平面内的询问点的答案+1,排序后用树状数组处理(类似扫描线),但不同的分治区间之间答案互不影响,所以对每个分治区间要分别开一个树状数组处理。
总时间复杂度O(nsqrt(n)logn)
upd:类似http://www.cnblogs.com/ccz181078/p/6607323.html的莫队做法可以去掉一个log,实际运行效果也更好
#include<bits/stdc++.h> const int inf=0x7fffffff; int _(){ int x=0,c=getchar(); while(c<48)c=getchar(); while(c>47)x=x*10+c-48,c=getchar(); return x; } int n,q,B,p2=0; int vs[50007][2],xs[50007]; struct Q{ int l,r,id; }qs[200007],q2[4000007]; bool operator<(Q a,Q b){ return a.l>b.l; } struct Q2{ int l,r; }q3[1000007]; bool operator<(Q2 a,Q2 b){ return a.l>b.l; } int idp=0,bit[133][50007],ans[200007],lr[50007][2]; void mins(int&a,int b){if(a>b)a=b;} void maxs(int&a,int b){if(a<b)a=b;} void calc(int l,int r){ if(r-l+1<=B)return; ++idp; int m=l+r>>1; int lmx=inf,rmn=0; for(int i=m+1;i<=r;++i){ mins(lmx,vs[i][1]); maxs(rmn,vs[i][0]); q2[p2++]=(Q){lmx,rmn,idp}; } lmx=inf,rmn=0; for(int i=m;i;--i){ mins(lmx,vs[i][1]); maxs(rmn,vs[i][0]); q2[p2++]=(Q){lmx,rmn,idp}; } calc(l,m); calc(m+1,r); } void inc(int*a,int w,int mx){ for(;w<=mx;w+=w&-w)++a[w]; } int sum(int*a,int w){ int s=0; for(;w;w-=w&-w)s+=a[w]; return s; } int main(){ n=_();q=_();B=sqrt(n*4); for(int i=1;i<=n;++i){ xs[i]=vs[i][0]=_(); vs[i][1]=_(); } std::sort(xs+1,xs+n+1); for(int i=1;i<=n;++i)vs[i][0]=std::lower_bound(xs+1,xs+n+1,vs[i][0])-xs; for(int i=1;i<=q;++i)qs[i].l=_(),qs[i].r=std::upper_bound(xs+1,xs+n+1,_())-xs-1,qs[i].id=i; std::sort(qs+1,qs+q+1); calc(1,n); std::sort(q2,q2+p2); for(int i=1,p=0;i<=q;++i){ for(;p<p2&&q2[p].l>=qs[i].l;++p)inc(bit[q2[p].id],q2[p].r,n+1); for(int j=1;j<=idp;++j){ maxs(ans[qs[i].id],sum(bit[j],qs[i].r)); } } for(int i=1;i<=n;++i)lr[i][0]=inf; for(int d=1;d<=B;++d){ p2=0; for(int l=1;l<=n;++l){ int r=l+d-1; if(r>n)break; mins(lr[l][0],vs[r][1]); maxs(lr[l][1],vs[r][0]); q3[p2++]=(Q2){lr[l][0],lr[l][1]}; } std::sort(q3,q3+p2); int rmn=inf; for(int i=1,p=0;i<=q;++i){ for(;p<p2&&q3[p].l>=qs[i].l;++p)mins(rmn,q3[p].r); if(rmn<=qs[i].r)maxs(ans[qs[i].id],d); } } for(int i=1;i<=q;++i)printf("%d\n",ans[i]); return 0; }