BZOJ5089: 最大连续子段和

2024-01-03 19:59
文章标签 最大 连续 子段 bzoj5089

本文主要是介绍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

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

转载于:https://www.cnblogs.com/Blue233333/p/8059606.html

这篇关于BZOJ5089: 最大连续子段和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/566882

相关文章

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

poj2406(连续重复子串)

题意:判断串s是不是str^n,求str的最大长度。 解题思路:kmp可解,后缀数组的倍增算法超时。next[i]表示在第i位匹配失败后,自动跳转到next[i],所以1到next[n]这个串 等于 n-next[n]+1到n这个串。 代码如下; #include<iostream>#include<algorithm>#include<stdio.h>#include<math.

XTU 1233 n个硬币连续m个正面个数(dp)

题面: Coins Problem Description: Duoxida buys a bottle of MaiDong from a vending machine and the machine give her n coins back. She places them in a line randomly showing head face or tail face o

poj 3723 kruscal,反边取最大生成树。

题意: 需要征募女兵N人,男兵M人。 每征募一个人需要花费10000美元,但是如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱。 给出若干的男女之间的1~9999之间的亲密关系度,征募某个人的费用是10000 - (已经征募的人中和自己的亲密度的最大值)。 要求通过适当的招募顺序使得征募所有人的费用最小。 解析: 先设想无向图,在征募某个人a时,如果使用了a和b之间的关系

poj 3258 二分最小值最大

题意: 有一些石头排成一条线,第一个和最后一个不能去掉。 其余的共可以去掉m块,要使去掉后石头间距的最小值最大。 解析: 二分石头,最小值最大。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <c

poj 2175 最小费用最大流TLE

题意: 一条街上有n个大楼,坐标为xi,yi,bi个人在里面工作。 然后防空洞的坐标为pj,qj,可以容纳cj个人。 从大楼i中的人到防空洞j去避难所需的时间为 abs(xi - pi) + (yi - qi) + 1。 现在设计了一个避难计划,指定从大楼i到防空洞j避难的人数 eij。 判断如果按照原计划进行,所有人避难所用的时间总和是不是最小的。 若是,输出“OPETIMAL",若

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

poj 2594 二分图最大独立集

题意: 求一张图的最大独立集,这题不同的地方在于,间接相邻的点也可以有一条边,所以用floyd来把间接相邻的边也连起来。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <sta

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 3692 二分图最大独立集

题意: 幼儿园里,有G个女生和B个男生。 他们中间有女生和女生认识,男生男生认识,也有男生和女生认识的。 现在要选出一些人,使得这里面的人都认识,问最多能选多少人。 解析: 反过来建边,将不认识的男生和女生相连,然后求一个二分图的最大独立集就行了。 下图很直观: 点击打开链接 原图: 现图: 、 代码: #pragma comment(