BZOJ2388: 旅行规划
n<=1e5个数,m<=1e5个操作:区间加,查区间最大的1~i号点的和。
第一次见到nsqrt(n)logn能过1e5的。。然而跑得很慢
普通数据结构感觉难下手,那就分块。先处理前缀和数组。一次修改,实际上把一段前缀和加上了一个等差数列,然后把这区间后面的前缀和加上某个固定数字,也可以看成另一个等差数列。等差数列叠加依然是等差数列,那就考虑整块打上一个A,B标记表示这一块加上首项(A+B)公差B的等差数列后的结果。
假设一块里的第i个数是Si,那如果i比j优(j>i),就有
$s_i+i*B+A>s_j+j*B+A$
整理得
$\frac{s_i-s_j}{j-i}>B$
嘿嘿,每个块维护个凸包就搞定了
实测块大小取150跑得比较快。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 #include<math.h> 6 //#include<time.h> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m,q; 11 #define maxn 100011 12 #define maxm 561 13 #define LL long long 14 int bel[maxn],tot; LL shou[maxm],cha[maxm],a[maxn],tu[maxm][maxm]; 15 double calc(int i,int j) {return 1.0*(a[i]-a[j])/(j-i);} 16 void maketu(int x) 17 { 18 int l=(x-1)*m+1,r=min(x*m,n); 19 tu[x][0]=0; 20 for (int i=l;i<=r;i++) 21 { 22 while (tu[x][0]>1 && calc(tu[x][tu[x][0]-1],tu[x][tu[x][0]])>=calc(tu[x][tu[x][0]],i)) tu[x][0]--; 23 tu[x][++tu[x][0]]=i; 24 } 25 } 26 void down(int x) 27 { 28 if (!shou[x] && !cha[x]) return; 29 int l=(x-1)*m+1,r=min(x*m,n); 30 for (int i=l,cnt=1;i<=r;i++,cnt++) a[i]+=shou[x]+cha[x]*cnt; 31 shou[x]=cha[x]=0; 32 } 33 void modifysingle(int x,int y,LL s,LL v) 34 { 35 if (x>y) return; 36 down(bel[x]); 37 for (int i=x,cnt=1;i<=y;i++,cnt++) a[i]+=s+cnt*v; 38 maketu(bel[x]); 39 } 40 void modify(int x,int y,LL v) 41 { 42 if (bel[x]==bel[y]) 43 { 44 modifysingle(x,y,0,v); 45 LL s1=(y-x+1)*v; 46 modifysingle(y+1,min(bel[y]*m,n),(y-x+1)*v,0); 47 for (int i=bel[y]+1;i<=tot;i++) shou[i]+=s1; 48 } 49 else 50 { 51 LL s1=(bel[x]*m-x+1)*v,s2=((bel[y]-1)*m-x+1)*v,s3=(y-x+1)*v; 52 for (int i=bel[x]+1;i<bel[y];i++) shou[i]+=s1,cha[i]+=v,s1+=m*v; 53 modifysingle(x,bel[x]*m,0,v); 54 modifysingle((bel[y]-1)*m+1,y,s2,v); 55 modifysingle(y+1,min(bel[y]*m,n),s3,0); 56 for (int i=bel[y]+1;i<=tot;i++) shou[i]+=s3; 57 } 58 } 59 LL querysingle(int x,int y) 60 { 61 down(bel[x]); 62 LL ans=-1e18; 63 for (int i=x;i<=y;i++) ans=max(ans,a[i]); 64 maketu(bel[x]); 65 return ans; 66 } 67 LL query(int x,int y) 68 { 69 if (bel[x]==bel[y]) return querysingle(x,y); 70 else 71 { 72 LL ans=-1e18; 73 for (int i=bel[x]+1;i<bel[y];i++) 74 { 75 int L=1,R=tu[i][0]; 76 while (L<R) 77 { 78 const int mid=(L+R)>>1; 79 if (calc(tu[i][mid],tu[i][mid+1])>=cha[i]) R=mid; 80 else L=mid+1; 81 } 82 ans=max(ans,a[tu[i][L]]+shou[i]+(tu[i][L]-(i-1)*m)*cha[i]); 83 } 84 ans=max(ans,querysingle(x,bel[x]*m)); 85 ans=max(ans,querysingle((bel[y]-1)*m+1,y)); 86 return ans; 87 } 88 } 89 int main() 90 { 91 scanf("%d",&n); 92 m=min(150,n); 93 for (int i=1;i<=n;i++) bel[i]=(i-1)/m+1; 94 tot=bel[n]; 95 96 for (int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1]; 97 for (int i=1;i<=tot;i++) maketu(i); 98 99 scanf("%d",&q); 100 int id,x,y,z; 101 while (q--) 102 { 103 scanf("%d",&id); 104 if (id) 105 { 106 scanf("%d%d",&x,&y); 107 printf("%lld\n",query(x,y)); 108 } 109 else 110 { 111 scanf("%d%d%d",&x,&y,&z); 112 modify(x,y,z); 113 } 114 } 115 return 0; 116 }