题解 P4192 旅行规划
Solution
使用分块 , 将每个点的 \(x\) 坐标设为它的下标减去块首下标 \(+1\) , \(y\) 坐标设为在此处下车的旅行价值 (前缀和) .
对于每个块我们计算出它的上凸包 , 用来维护最大值 .
对于每次修改的 \(x,y\) 之后的块 , 直接维护 \(sumtag\) 表示全局增量就可以 .
对于 \(x,y\) 所在的块 , 直接暴力重构 .
同时我们对每个块维护 \(addtag\) 表示这个区间里的美观度的全局增量
那么每个点的旅行价值即为 \(y+x* addtag+sumtag\) , 可以发现最大值所取到的点一定在凸包上 , 并且在 \(addtag\) 增大时向右移动 , 减小时向左移动 , 我们在做区间加时更新即可 . 一些细节见代码 .
复杂度 \(O(n\sqrt n)\)
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
int ret=0;bool f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=!f;c=getchar();}
while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?ret:-ret;
}
const int maxn=1e5+5;
const int maxm=320;
const ll inf=1e18;
int n,m;
struct point
{
ll x,y;
const bool operator <(const point &a)const{if(x!=a.x)return x<a.x;return y<a.y;}
const point operator -(const point &a)const{return point{x-a.x,y-a.y};}
const ll operator *(const point &a)const{return x*a.y-y*a.x;}
};
ll ori[maxn];
int siz,bl[maxn],bnum;
struct block
{
point p[maxm],convex[maxm];int top;
int num,nowmax;
ll sumtag,addtag;
void andrew()
{
top=1;
convex[1]=p[1];
for(int i=2;i<=num;i++)
{
while(top>=2&&(convex[top]-convex[top-1])*(p[i]-convex[top])>=0)top--;
convex[++top]=p[i];
}
for(int i=1;i<=top;i++)if(i==top||convex[i].y>=convex[i+1].y){nowmax=i;break;}
}
ll calc(point a){return a.y+a.x*addtag+sumtag;}
void rebuild()
{
for(int i=1;i<=num;i++)p[i].y=calc(p[i]);
sumtag=0;addtag=0;
andrew();
}
void add(int x)
{
addtag+=x;
if(x>0)while(nowmax!=top&&calc(convex[nowmax])<=calc(convex[nowmax+1]))nowmax++;
else while(nowmax!=1&&calc(convex[nowmax])<=calc(convex[nowmax-1]))nowmax--;
}
ll getmax(){return calc(convex[nowmax]);}
}b[maxm];
int main()
{
n=read();
siz=sqrt(n);
for(int i=1;i<=n;i++)bl[i]=(i-1)/siz+1;
for(int i=1;i<=n;i++)ori[i]=ori[i-1]+read();
for(int i=1;i<=n;i++)
{
b[bl[i]].num++;
int now=b[bl[i]].num;
b[bl[i]].p[now].x=now;
b[bl[i]].p[now].y=ori[i];
}
bnum=bl[n];
for(int i=1;i<=bnum;i++)b[i].rebuild();
m=read();
while(m--)
{
int type=read();
if(type==0)
{
int x,y,k;x=read();y=read();k=read();
if(bl[x]==bl[y])
{
for(int i=x;i<=y;i++)b[bl[x]].p[i-(bl[x]-1)*siz].y+=(ll)(i-x+1)*k;
for(int i=y+1;i<=min(n,bl[x]*siz);i++)b[bl[x]].p[i-(bl[x]-1)*siz].y+=(ll)(y-x+1)*k;
b[bl[x]].rebuild();
for(int i=bl[y]+1;i<=bnum;i++)b[i].sumtag+=(ll)(y-x+1)*k;
}
else
{
for(int i=x;i<=bl[x]*siz;i++)b[bl[x]].p[i-(bl[x]-1)*siz].y+=(ll)(i-x+1)*k;
for(int i=(bl[y]-1)*siz+1;i<=y;i++)b[bl[y]].p[i-(bl[y]-1)*siz].y+=(ll)k*(i-x+1);
for(int i=y+1;i<=min(n,bl[y]*siz);i++)b[bl[y]].p[i-(bl[y]-1)*siz].y+=(ll)k*(y-x+1);
b[bl[x]].rebuild();b[bl[y]].rebuild();
for(int i=bl[x]+1;i<=bl[y]-1;i++)b[i].add(k),b[i].sumtag+=(ll)((i-1)*siz-x+1)*k;
for(int i=bl[y]+1;i<=bnum;i++)b[i].sumtag+=(ll)(y-x+1)*k;
}
}
else if(type==1)
{
int x,y;x=read();y=read();
ll ret=-inf;
if(bl[x]==bl[y])
for(int i=x;i<=y;i++)ret=max(ret,b[bl[x]].calc(b[bl[x]].p[i-(bl[x]-1)*siz]));
else
{
for(int i=x;i<=bl[x]*siz;i++)ret=max(ret,b[bl[x]].calc(b[bl[x]].p[i-(bl[x]-1)*siz]));
for(int i=(bl[y]-1)*siz+1;i<=y;i++)ret=max(ret,b[bl[y]].calc(b[bl[y]].p[i-(bl[y]-1)*siz]));
for(int i=bl[x]+1;i<=bl[y]-1;i++)ret=max(ret,b[i].getmax());
}
printf("%lld\n",ret);
}
}
return 0;
}