codeforces 1136E-Nastya Hasn't Written a Legend

传送门:QAQQAQ

 

题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i]。有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质。比如a[i]加上x之后,a[i + 1]<a[i] + k[i],那么a[i + 1]就变成a[i] + k[i],否则不变。同理,若a[i + 2]小于了现在的a[i + 1] + k[i + 1],那么a[i + 2]也变成a[i + 1] + k[i + 1],一直保持这个性质。第二章操作,询问数组a的区间[l, r]的区间和。

 

思路:用另一个b数组保存a[i]-(k[1]+k[2]+...+k[i-1]),这样由题意的大小关系可知,b数组是非递减的。所以更新是只需在b[x]加上y用二分找出一段连续的需要被修改的区间即可,为节省时间,k应该用前缀和形式保存。

  查询时,只需利用b数组建造线段树并维护,求区间sum并加上之前每个b[i]被减掉的k即可,为节省时间,可以再前缀和k的基础上再加一个前缀和kk。这样查询时只需求query(1,1,n,l,r)+kk[r-1]-kk[l-2]。

注意:b数组只在建线段树时用到,因为后面b不再被更新,需要用query求出最新的b数组里的值; 赋值懒标记tag时一定要赋值成数据无法触碰到的值INF,否则会出现无法pushdown的情况(之前赋值成-1,在第7个点上调了老半天)。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N=200001;
  5 const ll inf=-1e18;
  6 
  7 ll n,a[N],b[N],k[N],kk[N],m;
  8 
  9 ll sum[N<<2],tag[N<<2];
 10 void build(int x,int l,int r)
 11 {
 12     if(l==r)
 13     { 
 14         sum[x]=b[l];
 15         return;
 16     }
 17     int mid=(l+r)>>1;
 18     build(x+x,l,mid);
 19     build(x+x+1,mid+1,r);
 20     sum[x]=sum[x+x]+sum[x+x+1];
 21 }
 22 
 23 void push_down(int x,int l,int r)
 24 {
 25     int mid=(l+r)>>1;
 26     if(tag[x]==inf) return;
 27     tag[x+x]=tag[x]; tag[x+x+1]=tag[x];
 28     sum[x+x]=tag[x]*(mid-l+1);
 29     sum[x+x+1]=tag[x]*(r-mid);
 30     tag[x]=inf;
 31 }
 32 
 33 void update(int x,int l,int r,int L,int R,ll val)
 34 {
 35     if(L<=l&&r<=R)
 36     {
 37         tag[x]=val;
 38         sum[x]=val*(r-l+1);
 39         return;
 40     }
 41     int mid=(l+r)>>1;
 42     push_down(x,l,r);
 43     if(mid>=R) update(x+x,l,mid,L,R,val);
 44     else if(mid<L) update(x+x+1,mid+1,r,L,R,val);
 45     else
 46     {
 47         update(x+x,l,mid,L,R,val);
 48         update(x+x+1,mid+1,r,L,R,val);
 49     }
 50     sum[x]=sum[x+x]+sum[x+x+1];
 51 }
 52 
 53 ll query(int x,int l,int r,int L,int R)
 54 {
 55     if(L>R) return 0;
 56     if(L<=l&&r<=R) return sum[x];
 57     int mid=(l+r)>>1;
 58     push_down(x,l,r);
 59     if(mid>=R) return query(x+x,l,mid,L,R);
 60     else if(mid<L) return query(x+x+1,mid+1,r,L,R);
 61     else
 62     {
 63         return query(x+x,l,mid,L,R)+query(x+x+1,mid+1,r,L,R);
 64     }
 65 }
 66 
 67 int main()
 68 {
 69     for(int i=0;i<(N<<2);i++) tag[i]=inf;
 70     scanf("%lld",&n);
 71     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
 72     for(int i=1;i<n;i++) scanf("%lld",&k[i]);
 73     for(int i=2;i<n;i++) k[i]+=k[i-1];
 74     for(int i=1;i<n;i++) kk[i]=kk[i-1]+k[i];
 75     for(int i=1;i<=n;i++) b[i]=a[i]-k[i-1];//feidijian
 76     build(1,1,n);
 77     scanf("%lld",&m);
 78     while(m--)
 79     {
 80         char s[2]; int x,y;
 81         scanf("%s%d%d",s,&x,&y);
 82         if(s[0]=='s')
 83         {
 84             ll add=kk[y-1]-(x>=2 ? kk[x-2] : 0);
 85             printf("%lld\n",add+query(1,1,n,x,y));
 86         }
 87         else
 88         {
 89             ll num=query(1,1,n,x,x)+y;//can't write b[x] instead of query(1,1,n,x,x)
 90             //int pos=lower_bound(b,b+n+1,num)-b;
 91             //can't use array b!
 92             int l=x,r=n,mid,pos=x;
 93             while(l<=r)
 94             {
 95                 mid=(l+r)>>1;
 96                 if(num>query(1,1,n,mid,mid))
 97                 {
 98                     pos=mid;
 99                     l=mid+1;
100                 }
101                 else r=mid-1;
102             }
103             update(1,1,n,x,pos,num); 
104         }
105     }
106     return 0;
107 }
View Code
posted @ 2019-04-20 14:12  'Clovers'  阅读(232)  评论(0编辑  收藏  举报