BZOJ5089: 最大连续子段和

维护一个序列支持以下操作:区间加,区间求最大子段和。n<=50000,m<=50000。

我TM再也不写分块了。。。

先分块,对于块整体加的操作,假设块里面有若干二元组(x,y),表示一个大小x的区间的和为y,那实际就是求kx+y=z的最大值,而y=-kx+z,所以即求经过这些点、斜率不定的直线的最大纵截距。而稍微画个图可知只有经过一个下凸包上的点的直线可能得到最大纵截距,故每个块维护之。由于区间加的数都是正数,所以查询均摊是O(size)的,而找出所有二元组的(x,y)需要O(size^2),均摊一下就size=n的立方根 即可。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<stdlib.h>
  5 #include<math.h>
  6 //#include<iostream>
  7 using namespace std;
  8 
  9 int n,m,q;
 10 #define maxn 50011
 11 #define maxm 55
 12 #define maxt 5011
 13 #define LL long long
 14 LL max(LL a,LL b) {return a>b?a:b;}
 15 LL a[maxn];
 16 struct Block
 17 {
 18     int l,r;
 19     LL add,tot;
 20     int num[maxm],lnum[maxm],rnum[maxm];
 21     LL Max[maxm],lmax[maxm],rmax[maxm];
 22     void down()
 23     {
 24         if (add) for (int i=l;i<=r;i++) a[i]+=add;
 25         add=0;
 26     }
 27     double calc(int i,int j) {return 1.0*(Max[i]-Max[j])/(i-j);}
 28     double lcalc(int i,int j) {return 1.0*(lmax[i]-lmax[j])/(i-j);}
 29     double rcalc(int i,int j) {return 1.0*(rmax[i]-rmax[j])/(i-j);}
 30     void build()
 31     {
 32         int len=r-l+1;
 33         
 34         for (int i=1;i<=len;i++) Max[i]=-1e18;
 35         for (int i=l;i<=r;i++)
 36         {
 37             LL now=0;
 38             for (int j=i;j<=r;j++)
 39             {
 40                 now+=a[j];
 41                 Max[j-i+1]=max(Max[j-i+1],now);
 42             }
 43         }
 44         num[0]=0;
 45         for (int i=1;i<=len;i++)
 46         {
 47             while (num[0]>1 && (calc(num[num[0]],num[num[0]-1])<calc(i,num[num[0]]))) num[0]--;
 48             num[++num[0]]=i;
 49         }
 50         num[num[0]+1]=1;
 51         
 52         lnum[0]=0;
 53         lmax[0]=0;
 54         for (int i=1;i<=len;i++) lmax[i]=lmax[i-1]+a[l+i-1];
 55         for (int i=1;i<=len;i++)
 56         {
 57             while (lnum[0]>1 && (lcalc(lnum[lnum[0]],lnum[lnum[0]-1])<lcalc(i,lnum[lnum[0]]))) lnum[0]--;
 58             lnum[++lnum[0]]=i;
 59         }
 60         lnum[lnum[0]+1]=1;
 61         
 62         rnum[0]=0;
 63         rmax[0]=0;
 64         for (int i=1;i<=len;i++) rmax[i]=rmax[i-1]+a[r-i+1];
 65         for (int i=1;i<=len;i++)
 66         {
 67             while (rnum[0]>1 && (rcalc(rnum[rnum[0]],rnum[rnum[0]-1])<rcalc(i,rnum[rnum[0]]))) rnum[0]--;
 68             rnum[++rnum[0]]=i;
 69         }
 70         rnum[rnum[0]+1]=1;
 71         
 72         tot=0;
 73         for (int i=l;i<=r;i++) tot+=a[i];
 74     }
 75     LL getans()
 76     {
 77         while (num[num[0]+1]<num[0] && calc(num[num[num[0]+1]+1],num[num[num[0]+1]])>-add)
 78             num[num[0]+1]++;
 79         return max(num[num[num[0]+1]]*add+Max[num[num[num[0]+1]]],0ll);
 80     }
 81     LL getlans()
 82     {
 83         while (lnum[lnum[0]+1]<lnum[0] && lcalc(lnum[lnum[lnum[0]+1]+1],lnum[lnum[lnum[0]+1]])>-add)
 84             lnum[lnum[0]+1]++;
 85         return max(lnum[lnum[lnum[0]+1]]*add+lmax[lnum[lnum[lnum[0]+1]]],0ll);
 86     }
 87     LL getrans()
 88     {
 89         while (rnum[rnum[0]+1]<rnum[0] && rcalc(rnum[rnum[rnum[0]+1]+1],rnum[rnum[rnum[0]+1]])>-add)
 90             rnum[rnum[0]+1]++;
 91         return max(rnum[rnum[rnum[0]+1]]*add+rmax[rnum[rnum[rnum[0]+1]]],0ll);
 92     }
 93 }b[maxt];
 94 
 95 int bel[maxn],tot;
 96 void modify(int x,int y,int v)
 97 {
 98     if (bel[x]==bel[y])
 99     {
100         b[bel[x]].down();
101         for (int i=x;i<=y;i++) a[i]+=v;
102         b[bel[x]].build();
103     }
104     else
105     {
106         int z=b[bel[x]].r;
107         b[bel[x]].down();
108         for (int i=x;i<=z;i++) a[i]+=v;
109         b[bel[x]].build();
110         z=b[bel[y]].l;
111         b[bel[y]].down();
112         for (int i=y;i>=z;i--) a[i]+=v;
113         b[bel[y]].build();
114         for (int i=bel[x]+1;i<bel[y];i++) b[i].add+=v;
115     }
116 }
117 LL query(int x,int y)
118 {
119     if (bel[x]==bel[y])
120     {
121         b[bel[x]].down();
122         b[bel[x]].build();
123         LL ans=0,now=0;
124         for (int i=x;i<=y;i++)
125         {
126             now+=a[i];
127             if (now<0) now=0;
128             ans=max(ans,now);
129         }
130         return ans;
131     }
132     else
133     {
134         b[bel[x]].down();
135         b[bel[x]].build();
136         b[bel[y]].down();
137         b[bel[y]].build();
138         int z=b[bel[x]].r;
139         LL ans=0,rans=0,now=0;
140         for (int i=x;i<=z;i++)
141         {
142             now+=a[i];
143             if (now<0) now=0;
144             ans=max(ans,now);
145         }
146         LL tot=0;
147         for (int i=z;i>=x;i--)
148         {
149             tot+=a[i];
150             rans=max(rans,tot);
151         }
152         for (int i=bel[x]+1;i<bel[y];i++)
153         {
154             LL ll=b[i].getlans(),rr=b[i].getrans(),tt=b[i].tot+(b[i].r-b[i].l+1)*b[i].add;
155             ans=max(ans,max(b[i].getans(),ll+rans));
156             rans=max(0,max(rr,rans+tt));
157         }
158         z=b[bel[y]].l;
159         for (int i=z;i<=y;i++)
160         {
161             rans+=a[i];
162             if (rans<0) rans=0;
163             ans=max(ans,rans);
164         }
165         return ans;
166     }
167 }
168 int main()
169 {
170     scanf("%d%d",&n,&q);
171     m=40;
172     for (int i=1;i<=n;i++) bel[i]=(i-1)/m+1;
173     tot=bel[n];
174     for (int i=1;i<tot;i++) b[i].l=(i-1)*m+1,b[i].r=i*m;
175     b[tot].l=(tot-1)*m+1,b[tot].r=n;
176     
177     for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
178     for (int i=1;i<=tot;i++) b[i].build();
179     
180     char id[5];int x,y,z;
181     while (q--)
182     {
183         scanf("%s",id);
184         if (id[0]=='A')
185         {
186             scanf("%d%d%d",&x,&y,&z);
187             modify(x,y,z);
188         }
189         else
190         {
191             scanf("%d%d",&x,&y);
192             printf("%lld\n",query(x,y));
193         }
194     }
195     return 0;
196 }
View Code

我就是死外边,从这里跳下去,我也不再写分块!

posted @ 2017-12-18 21:04  Blue233333  阅读(441)  评论(0编辑  收藏  举报