題解 P4192 旅行規劃
阿新 • • 發佈:2021-06-20
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; }