[cf573E]Bear and Bowling

结论:假设$a_{x}=\max_{i=1}^{n}a_{i}$,对于任意$1\le l\le n$,存在长度为$l$且价值最大的子序列包含$x$

若不存在,任取一个长度为$l$且价值最大的子序列,将其中与$a_{x}$相邻的一项改为$a_{x}$即可

由此,不妨先选择$a_{x}$,并将$x$之前的元素加上$a_{x}$、$x$之后的元素加上自身,进而即变为子问题,重复此过程即可得到任意长度价值最大的子序列,显然其中最大值也即答案

提取这个问题的模型,即维护$\{a_{i}\}$和$\{w_{i}=k_{i}a_{i}+(s_{i}+a_{i})\}$,并支持:

1.给定$l$和$r$,令$\forall l\le i\le r,w_{i}=w_{i}+a_{i}$

2.给定$l,r$和$x$,令$\forall l\le i\le r,w_{i}=w_{i}+x$

3.查询$\max_{i=1}^{n}w_{i}$

操作1和操作3的实现可以参考[CF1178G],同时操作2可以快速维护该节点上信息,那么直接打懒标记即可,势能影响同样至多为$o(\log^{3}n)$

类似地,也可以支持$a_{i}$区间加和$a_{i},w_{i}$同时区间乘(相同的数),另外当乘上负数时可能还需要维护一个区间最小值并将两者交换(这里的$a_{i}$即上面那题的$k_{i}$)

最终,总复杂度为$o(n\log^{2}n+m_{1}\log^{3}n+m_{2}\log n+m_{3}\log^{3}n)$,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 #define ll long long
  5 #define L (k<<1)
  6 #define R (L+1)
  7 #define mid (l+r>>1)
  8 vector<int>v[N];
  9 int n,x,a[N];
 10 ll sum,ans;
 11 struct Seg{
 12     int tag_x[N<<2],mn[N<<2];
 13     ll tag_w[N<<2];
 14     struct Line{
 15         int k;
 16         ll b;
 17     }f[N<<2];
 18     double get_point(Line x,Line y){
 19         if (x.k==y.k)return 0x3f3f3f3f;
 20         return -1.0*(x.b-y.b)/(x.k-y.k);
 21     }
 22     void upd_x(int k,int x){
 23         tag_x[k]+=x,mn[k]-=x;
 24         f[k].b+=(ll)x*f[k].k;
 25     }
 26     void upd_w(int k,ll x){
 27         tag_w[k]+=x,f[k].b+=x;
 28     }
 29     void up(int k){
 30         double s=get_point(f[L],f[R]);
 31         if (s<0)s=0x3f3f3f3f;
 32         s=min(s,(double)0x3f3f3f3f);
 33         mn[k]=min(min(mn[L],mn[R]),(int)floor(s));
 34         if (f[L].b>f[R].b)f[k]=f[L];
 35         else f[k]=f[R];
 36     }
 37     void down(int k){
 38         upd_x(L,tag_x[k]),upd_x(R,tag_x[k]);
 39         upd_w(L,tag_w[k]),upd_w(R,tag_w[k]);
 40         tag_x[k]=tag_w[k]=0;
 41     }
 42     void build(int k,int l,int r){
 43         tag_x[k]=tag_w[k]=0;
 44         if (l==r){
 45             mn[k]=0x3f3f3f3f;
 46             return;
 47         }
 48         build(L,l,mid);
 49         build(R,mid+1,r);
 50         up(k);
 51     }
 52     void update(int k,int l,int r,int x,Line y){
 53         if (l==r){
 54             f[k]=y;
 55             return;
 56         }
 57         down(k);
 58         if (x<=mid)update(L,l,mid,x,y);
 59         else update(R,mid+1,r,x,y);
 60         up(k);
 61     }
 62     void update_x(int k,int l,int r,int x,int y,int z){
 63         if ((l>y)||(x>r))return;
 64         if ((x<=l)&&(r<=y)&&(mn[k]>=z)){
 65             upd_x(k,z);
 66             return;
 67         }
 68         down(k);
 69         update_x(L,l,mid,x,y,z);
 70         update_x(R,mid+1,r,x,y,z);
 71         up(k);
 72     }
 73     void update_w(int k,int l,int r,int x,int y,int z){
 74         if ((l>y)||(x>r))return;
 75         if ((x<=l)&&(r<=y)){
 76             upd_w(k,z);
 77             return;
 78         }
 79         down(k);
 80         update_w(L,l,mid,x,y,z);
 81         update_w(R,mid+1,r,x,y,z);
 82         up(k);
 83     }
 84     int query(int k,int l,int r){
 85         if (l==r)return l;
 86         down(k);
 87         if ((f[k].k==f[L].k)&&(f[k].b==f[L].b))return query(L,l,mid);
 88         return query(R,mid+1,r);
 89     }
 90 }T;
 91 int main(){
 92     scanf("%d",&n);
 93     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
 94     T.build(1,1,n);
 95     for(int i=1;i<=n;i++)T.update(1,1,n,i,Seg::Line{a[i],a[i]});
 96     for(int i=1;i<=n;i++){
 97         sum+=T.f[1].b,ans=max(ans,sum);
 98         int x=T.query(1,1,n);
 99         T.update(1,1,n,x,Seg::Line{0,(ll)-1e18});
100         T.update_x(1,1,n,x+1,n,1);
101         T.update_w(1,1,n,1,x-1,a[x]);
102     }
103     printf("%lld\n",ans);
104     return 0;
105 }
View Code

 

posted @ 2021-10-12 13:34  PYWBKTDA  阅读(45)  评论(0编辑  收藏  举报