BZOJ 2388: 旅行规划 [分块 凸包 等差数列]
题意:
区间加和询问一段区间内整体前缀和的最大值
刚才还在想做完这道题做一道区间加等差数列结果发现这道就是....
唯一的不同在于前缀和一段区间加上等差数列后,区间后面也要加上一个常数!!!
线段树没法搞吧....分块!
每个块维护整体加标记,首项,公差
修改的时候:
左面不完整的块下放标记暴力重构;
中间的整块打标记;
右面不完整的块也是下放标记暴力重构,注意这个地方$r$之外的部分也要更新!
右面完整的块也要打标记!
怎么查询呢?
左右不完整的块暴力查询
中间的整块,可以发现我们每次修改的只有公差会造成影响,类似于斜率,凸包的形状不会改变(斜率的相对大小不会改变),所以维护一个凸包,查询时三分就行了
其实我现在还不会三分就去黄学长哪里抄了一个奇怪的东西
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=1e5+5,M=350; const ll INF=1e18; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,Q,op,x,y; ll a[N]; struct _blo{int l,r;}b[M]; int block,m,pos[N]; inline void ini(){ block=sqrt(n); m=(n-1)/block+1; for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1; for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1 , b[i].r=i*block; b[m].r=n; } struct ConvexHull{ int a[M],n; int& operator [](int x){return a[x];} }con[M]; int st[N]; struct Block{ inline double slope(int i,int j){return (double)(a[i]-a[j])/(i-j);} void Set(int x){ int top=0; for(int i=b[x].l ; i<=b[x].r ; i++){ while(top>1 && slope(i,st[top-1])>=slope(st[top],st[top-1]) ) top--; st[++top]=i; } for(int i=1;i<=top;i++) con[x][i]=st[i]; con[x].n=top; con[x][0]=con[x][top+1]=0; } ll f[M],d[M],add[M]; void pushDown(int x){ ll now=f[x]; for(int i=b[x].l ; i<=b[x].r ; i++) a[i]+=now+add[x],now+=d[x]; f[x]=d[x]=add[x]=0; } void Add(int l,int r,ll v){ int pl=pos[l],pr=pos[r]; ll now=0; if(pl==pr){ pushDown(pl); for(int i=l;i<=r;i++) now+=v,a[i]+=now; for(int i=r+1 ; i<=b[pr].r ; i++) a[i]+=now; Set(pl); for(int i=pr+1;i<=m;i++) add[i]+=now; }else{ pushDown(pl); for(int i=l ; i<=b[pl].r ; i++) now+=v,a[i]+=now; Set(pl); for(int i=pl+1;i<pr;i++) now+=v,f[i]+=now,d[i]+=v,now+=v*(block-1); pushDown(pr); for(int i=b[pr].l ; i<=r ; i++) now+=v,a[i]+=now; for(int i=r+1 ; i<=b[pr].r ;i++) a[i]+=now; Set(pr); for(int i=pr+1;i<=m;i++) add[i]+=now; } } inline ll cal(int x){ if(x==0) return -INF;//!!!!! int t=pos[x]; return a[x]+add[t] + f[t]+d[t]*(x-b[t].l) ; } ll Bin(int x){ int l=1,r=con[x].n; while(l<=r){ int mid=(l+r)>>1; ll a=cal(con[x][mid-1]),b=cal(con[x][mid]),c=cal(con[x][mid+1]); if(a<b&&b<c) l=mid+1; else if(a>b&&b>c) r=mid-1; else return b; } return 0; } ll Que(int l,int r){ int pl=pos[l],pr=pos[r]; ll re=-INF; if(pl==pr) for(int i=l;i<=r;i++) re=max(re,cal(i)); else{ for(int i=l ; i<=b[pl].r ; i++) re=max(re,cal(i)); for(int i=b[pr].l ; i<=r ; i++) re=max(re,cal(i)); for(int i=pl+1;i<pr;i++) re=max(re,Bin(i)); } return re; } }B; int main(){ freopen("in","r",stdin); n=read(); ini(); for(int i=1;i<=n;i++) a[i]=read()+a[i-1]; for(int i=1;i<=m;i++) B.Set(i); Q=read(); while(Q--){ op=read();x=read();y=read(); if(op==0) B.Add(x,y,read()); else printf("%lld\n",B.Que(x,y)); } }
Copyright:http://www.cnblogs.com/candy99/