凸包好题
我一开始想的是线段树或平衡树维护最大前缀和,但是区间修改很恶心,后来想分块,发现貌似可以做,修改的话,中间的块打标记,两边的暴力重构,查询的话就是整块二分斜率为零的地方,边上的暴力查询。$O(nsqrt(n)log(n))$
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 #define N 100050 8 #define inf 0x7fffffffffffffff 9 #define int long long 10 using namespace std; 11 struct point{ 12 int x[2]; 13 point(){} 14 point(int a,int b){x[0]=a,x[1]=b;} 15 int operator * (point a){return x[0]*a.x[1]-x[1]*a.x[0];} 16 point operator + (point a){return point(x[0]+a.x[0],x[1]+a.x[1]);} 17 point operator - (point a){return point(x[0]-a.x[0],x[1]-a.x[1]);} 18 bool operator < (const point & a)const{ 19 if(x[0]==a.x[0])return x[1]<a.x[1]; 20 return x[0]<a.x[0]; 21 } 22 }p[N],K; 23 vector <int> v[1005]; 24 int be[N],en[N],n,nn,m; 25 int s[N],r[N]; 26 void init(){ 27 for(int i=1;i<=be[n];i++){ 28 for(int j=en[i-1]+1,sz;j<=en[i];j++){ 29 sz=v[i].size(); 30 while(sz>1&&(p[v[i][sz-1]]-p[v[i][sz-2]])*(p[j]-p[v[i][sz-1]])>=0)sz--,v[i].pop_back(); 31 v[i].push_back(j); 32 } 33 } 34 } 35 void work(int x){ 36 v[x].clear(); 37 for(int i=en[x-1]+1,sz;i<=en[x];i++){ 38 sz=v[x].size(); 39 while(sz>1&&(p[v[x][sz-1]]-p[v[x][sz-2]])*(p[i]-p[v[x][sz-1]])>=0)sz--,v[x].pop_back(); 40 v[x].push_back(i); 41 } 42 } 43 void update(int x,int l,int r,int val){ 44 if(!s[x]&&!::r[x]&&!val)return ; 45 for(int i=en[x-1]+1;i<=en[x];i++){ 46 p[i].x[1]+=s[x]+(i-en[x-1]-1)*::r[x]; 47 if(i>=l&&i<=r)p[i].x[1]+=(i-l+1)*val; 48 if(i>r)p[i].x[1]+=(r-l+1)*val; 49 } 50 s[x]=::r[x]=0; 51 work(x); 52 } 53 int query(int x){ 54 int l=1,r=v[x].size()-1,mid,ans=0; 55 point P=point(1,0); 56 while(l<=r){ 57 mid=(l+r)>>1; 58 point now=p[v[x][mid]];now.x[1]+=s[x]+::r[x]*(v[x][mid]-en[x-1]-1); 59 point last=p[v[x][mid-1]];last.x[1]+=s[x]+::r[x]*(v[x][mid-1]-en[x-1]-1); 60 if((now-last)*P<=0)ans=mid,l=mid+1; 61 else r=mid-1; 62 } 63 return p[v[x][ans]].x[1]+s[x]+::r[x]*(v[x][ans]-en[x-1]-1); 64 } 65 signed main(){ 66 scanf("%lld",&n);nn=sqrt(n); 67 p[0]=point(0,0); 68 K.x[0]=1; 69 for(int i=1;i<=n;i++){ 70 scanf("%lld",&K.x[1]); 71 p[i]=p[i-1]+K; 72 be[i]=(i-1)/nn+1; 73 } 74 for(int i=1;i<=be[n];i++)en[i]=min(i*nn,n); 75 init(); 76 scanf("%lld",&m); 77 int o,x,y,z,ans; 78 while(m--){ 79 scanf("%lld",&o); 80 if(o==0){ 81 scanf("%lld%lld%lld",&x,&y,&z); 82 update(be[x],x,y,z); 83 if(be[x]!=be[y])update(be[y],x,y,z); 84 for(int i=be[x]+1;i<be[y];i++){ 85 s[i]+=(en[i-1]+1-x+1)*z; 86 r[i]+=z; 87 } 88 for(int i=be[y]+1;i<=be[n];i++) 89 s[i]+=(y-x+1)*z; 90 } 91 else{ 92 ans=-inf; 93 scanf("%lld%lld",&x,&y); 94 for(int i=x;i<=min(en[be[x]],y);i++) 95 ans=max(ans,p[i].x[1]+s[be[x]]+r[be[x]]*(i-en[be[x]-1]-1)); 96 if(be[x]!=be[y]) 97 for(int i=en[be[y]-1]+1;i<=y;i++) 98 ans=max(ans,p[i].x[1]+s[be[y]]+r[be[y]]*(i-en[be[y]-1]-1)); 99 for(int i=be[x]+1;i<be[y];i++) 100 ans=max(ans,query(i)); 101 printf("%lld\n",ans); 102 } 103 } 104 return 0; 105 }