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 }
View Code

 

posted @ 2017-12-15 13:40  Blue233333  阅读(288)  评论(0编辑  收藏  举报