【Ynoi2013】D2T2

分块,分治。

题目大意:

给定一个长度为 n 的序列,多次询问,每次给出 l,r,L,R,需要求出,只保留权值在 [L,R] 中的数,其他数的权值为 0 时,区间 [l,r] 的最大子段和。

题解:

第七分块太难了就先来写一下这个。

结果交了 59 发才过……

有一个非常简单的做法,将值域离散化之后对值域进行莫队,用线段树维护最大子段和。时间复杂度为 O(nmlogn)

考虑更优的做法。如果我们有一种时间复杂度 O(n2) 的做法求出一个长度为 n 的序列的所有不同值域限制下的全局最大子段和,那我们就可以通过分块将这个复杂度降为 O(nn)

关于最大子段和的问题,分治是一个常见的思路。由于长度为 n 的序列,只有 O(n2) 个本质不同的值域限制,所以我们希望每层都能 O(n2) 合并信息。这样分治的复杂度为 T(n)=2T(n2)+O(n2)。根据主定理即可得到 T(n)=O(n2)

我们考虑已知两个子区间的本质不同的值以及限制,如何合并为这一层的答案。对于合并上来的 [L,R],我们需要在左、右分别找到区间 [L1,R1][L2,R2],其中 [L1,R1][L2,R2] 都是被 [L,R] 包含的最大区间。那么这两个区间的最大子段和信息进行合并,即可得到 [L,R] 的最大子段和信息。

我们考虑预处理对每个 L,左、右区间第一个大于等于 L 的值。同样,对于 R,预处理左、右区间第一个小于等于 R 的值。由于我们是要选最大的两个区间合并,那么两个端点和 L,R 最接近的一定是最大的。这样就可以直接 O(n2) 枚举 L,R,然后 O(1) 找到两个需要合并的区间,进行合并。

分治的时空复杂度均为 O(n2),考虑对序列分块,每个块的大小为 O(n),则对每个块进行分治的时间复杂度为 O(n)。分治花费的时间复杂度为 O(nn)

对于一个询问,拆成整块的和边角的。对于边界的显然可以 O(n) 解决。对于整块的,我们已经知道所有本质不同的值域限制的答案,那么对于值域限制为 [L,R] 的询问,我们要找到被它包含的最大的区间的信息。那么和上面的处理方式相同,对每个 LR 分别找到最靠近的端点即可。这里为了保证复杂度,必须用双指针处理,否则时间复杂度将退化为 O(mnlogn)

由于直接存储所有块的信息需要 O(nn) 的空间,无法接受。所以我们对询问离线,在一个块的信息处理完后,直接把这个块对所有询问的贡献都更新掉。这样空间复杂度为 O(n)

时间复杂度为 O((n+m)n)

注意实现时的常数。

Code:

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<functional>
  6. using namespace std;
  7. typedef long long LoveLive;
  8. typedef unsigned long long ULL;
  9. #define bel(x)((x-1)/siz+1)
  10. const int N=1e5+5,siz=200,B=siz+2;
  11. char buf[(int)1e7],*ss=buf;
  12. inline int init(){buf[fread(buf,1,(int)1e7-1,stdin)]='\n';fclose(stdin);return 0;}
  13. const int __START__=init();
  14. inline int readint(){
  15. int d=0;bool f=0;
  16. while(!isdigit(*ss))f=*ss++=='-';
  17. while(isdigit(*ss))d=d*10+(*ss++^'0');
  18. return f?-d:d;
  19. }
  20. char bwf[5000005],*ww=bwf;
  21. int xx[24];
  22. inline void print(LoveLive x){
  23. static int*q=xx;
  24. if(!x)*ww++='0';else{
  25. for(;x;x/=10)*q++=(x%10)^'0';
  26. while(q!=xx)*ww++=*--q;
  27. }
  28. *ww++='\n';
  29. }
  30. int n,m,A[N],a[B],beL[N],beR[N],b[B],tmp[B],vec[B];
  31. struct data{
  32. LoveLive lmax,rmax,mx,sum;
  33. inline data(LoveLive a,LoveLive b,LoveLive c,LoveLive d):lmax(a),rmax(b),mx(c),sum(d){}
  34. inline data(){lmax=rmax=mx=sum=0;}
  35. inline data(LoveLive x){sum=x,lmax=rmax=mx=max(x,0LL);}
  36. inline data operator+(const data&rhs)const{
  37. return(data){max(lmax,sum+rhs.lmax),max(rhs.rmax,rhs.sum+rmax),max({mx,rhs.mx,rmax+rhs.lmax}),sum+rhs.sum};
  38. }
  39. inline void operator+=(const data&rhs){mx=max({mx,rhs.mx,rmax+rhs.lmax}),lmax=max(lmax,sum+rhs.lmax),rmax=max(rhs.rmax,rhs.sum+rmax),sum+=rhs.sum;}
  40. }ans[N],p[65536],Lt[65536],Rt[65536];
  41. ULL lf[N],rg[N];
  42. int IT[B];
  43. struct que{
  44. int l,r,L,R;
  45. }q[N];
  46. struct info{
  47. int zt;
  48. data s;
  49. }D[600000],*ed;
  50. void solve(int l,int r,info*V,int&tot){
  51. if(l==r){
  52. V[tot++]=(info){a[l]<<8|a[l],data(vec[a[l]])};
  53. return;
  54. }
  55. const int mid=l+r>>1;
  56. info*L=ed;ed+=(mid-l+1)*(mid-l+2);
  57. info*R=ed;ed+=(r-mid+1)*(r-mid);
  58. int cntL=0,cntR=0;
  59. solve(l,mid,L,cntL),solve(mid+1,r,R,cntR);
  60. int i=l,j=mid+1,t=l,k;
  61. while(i<=mid&&j<=r)if(b[i]<=b[j])tmp[t++]=b[i++];else tmp[t++]=b[j++];
  62. while(i<=mid)tmp[t++]=b[i++];while(j<=r)tmp[t++]=b[j++];
  63. for(int i=0;i<cntL;++i)Lt[L[i].zt]=L[i].s;
  64. for(int i=0;i<cntR;++i)Rt[R[i].zt]=R[i].s;
  65. static int _L[B],_R[B],L_[B],R_[B];
  66. t=l,k=mid+1;
  67. for(int i=l;i<=r;++i){
  68. while(t<=mid&&b[t]<tmp[i])++t;
  69. while(k<=r&&b[k]<tmp[i])++k;
  70. _L[i]=t<=mid?b[t]:114514,L_[i]=k<=r?b[k]:114514;
  71. }
  72. t=mid,k=r;
  73. for(int i=r;i>=l;--i){
  74. while(t>=l&&b[t]>tmp[i])--t;
  75. while(k>mid&&b[k]>tmp[i])--k;
  76. _R[i]=t>=l?b[t]:0,R_[i]=k>mid?b[k]:0;
  77. }
  78. for(int i=l;i<=r;++i)b[i]=tmp[i];
  79. for(int i=l;i<=r;++i)if(i==l||b[i]!=b[i-1])
  80. for(int j=i;j<=r;++j)if(j==i||b[j]!=b[j-1]){
  81. const data&ztL=Lt[_L[i]<<8|_R[j]],&ztR=Rt[L_[i]<<8|R_[j]];const int X=b[i]<<8|b[j];
  82. if(_L[i]<=_R[j]&&L_[i]<=R_[j])V[tot++]=(info){X,ztL+ztR};else
  83. if(_L[i]<=_R[j])V[tot++]=(info){X,ztL};else
  84. if(L_[i]<=R_[j])V[tot++]=(info){X,ztR};
  85. }
  86. ed=L;
  87. }
  88. inline data get(int l,int r,const int&L,const int&R){
  89. LoveLive lm=0,rm=0,sum=0,mx=0,s=0;
  90. for(int i=l;i<=r;++i)if(lm<(s+=(L<=A[i]&&A[i]<=R)?A[i]:0))lm=s;
  91. s=0;
  92. for(int i=r;i>=l;--i)if(rm<(s+=(L<=A[i]&&A[i]<=R)?A[i]:0))rm=s;
  93. s=0;
  94. for(int i=l;i<=r;++i){
  95. const int x=(L<=A[i]&&A[i]<=R)?A[i]:0;
  96. sum+=x,s+=x;
  97. if(mx<s)mx=s;
  98. if(s<0)s=0;
  99. }
  100. return data(lm,rm,mx,sum);
  101. }
  102. int main(){
  103. n=readint(),m=readint();
  104. for(int i=1;i<=n;++i)A[i]=readint();
  105. for(int i=1;i<=m;++i){
  106. int l=readint(),r=readint(),L=readint(),R=readint();
  107. q[i]=(que){l,r,L,R},L+=1000000000,R+=1000000000,lf[i]=(ULL)L<<32|i,rg[i]=(ULL)R<<32|i;
  108. }
  109. sort(lf+1,lf+m+1),sort(rg+1,rg+m+1,greater<ULL>());
  110. for(int l=siz+1,r=2*siz;r<=n;l+=siz,r+=siz){
  111. int len=r-l+1;
  112. for(int i=l;i<=r;++i)vec[i-l]=A[i];
  113. int Val=len;
  114. sort(vec,vec+len);
  115. Val=unique(vec,vec+len)-vec;
  116. for(int i=l;i<=r;++i)a[i-l]=lower_bound(vec,vec+Val,A[i])-vec;
  117. memcpy(b,a,sizeof a);
  118. int tp=0;
  119. ed=D+len*(len+1);
  120. solve(0,len-1,D,tp);
  121. for(int i=0;i<tp;++i)p[D[i].zt]=D[i].s;
  122. int it1=0,it2=Val-1;
  123. for(int i=1;i<=m;++i){
  124. while(it1<Val&&(lf[i]>>32)>vec[it1]+1000000000)++it1;
  125. while(~it2&&(rg[i]>>32)<vec[it2]+1000000000)--it2;
  126. beL[(int)lf[i]]=it1,beR[(int)rg[i]]=it2;
  127. }
  128. for(int i=1;i<=m;++i)if(beL[i]<=beR[i]&&q[i].l<l&&r<q[i].r)ans[i]+=p[beL[i]<<8|beR[i]];
  129. }
  130. for(int i=1;i<=m;++i){
  131. int l=q[i].l,r=q[i].r;
  132. const int bL=bel(l),bR=bel(r);
  133. if(bL==bR)print(get(l,r,q[i].L,q[i].R).mx);else
  134. print((get(l,bL*siz,q[i].L,q[i].R)+ans[i]+get((bR-1)*siz+1,r,q[i].L,q[i].R)).mx);
  135. }
  136. fwrite(bwf,ww-bwf,1,stdout);
  137. return 0;
  138. }

Gitalking ...