seq 差分

Description

白云建立了n个商店,白兔打算按照编号1 . . . n的顺序访问这些商店。 商店i有一个
价格a i 表示交易商品所需的代价。
白兔在按顺序走时,每到达一个商店,可以花费代价购买一件商品,并放入自己手
中。也可以出售手上的商品,并获得利润。
白兔的力量有限,同一时刻只能携带一个商品。问它遍历完所有商店后能够获得的
利润最大是多少?
白兔的精力也有限,所以,在最大化利润的前提下,它想让交易次数尽可能地少。
当然,白云不想让白兔轻松获利,它有时会命令一段区间内的商店把价格同时加上
一个数。

solution

显然是找到许多个递增段,每一次该段的最大值减去最小值,我们可以线段树维护这个东西,但是有一个巧妙的差分思想:我们该原数组为差分数组后,问题就转化为求所有正数和,修改也变成了单点修改,第一问就做完了,第二问我们只需要特判一个 \(0\) 即可,我们维护正数区间的段,直接线段树合并时维护即可,我们发现如果0和一个正数接在一起,我们可以当做一段,这样就达到了第二问最小化购买的要求

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>

#define RG register
#define il inline
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))

#define ls (node<<1)
#define rs (node<<1|1)
using namespace std;
const int N=100005;
typedef long long ll;
int n,Q,a[N];
ll tot=0;
int tr[N<<2],fi[N<<2],suf[N<<2],sum[N<<2];

il void upd(int node){
   tr[node]=tr[ls]+tr[rs]-(suf[ls]&sum[rs]);
   suf[node]=suf[rs]|(fi[rs]&suf[ls]);
   sum[node]=sum[ls]|(fi[ls]&sum[rs]);
   fi[node]=fi[ls]&fi[rs];
}

il void ins(int l,int r,int node,int sa){
   if(l==r){
      suf[node]=sum[node]=tr[node]=a[sa]>0,fi[node]=a[sa]==0;
      return ;
   }
   int mid=(l+r)>>1;
   if(sa<=mid)ins(l,mid,ls,sa);
   else ins(mid+1,r,rs,sa);
   upd(node);
}

il void build(int l,int r,int node){
   if(l==r){
      suf[node]=sum[node]=tr[node]=a[l]>0,fi[node]=a[l]==0;
      return ;
   }
   int mid=(l+r)>>1;
   build(l,mid,ls);build(mid+1,r,rs);
   upd(node);
}

void Clear(){
   int lim=N*4-1;
   for(RG int i=0;i<lim;i++)
      tr[i]=fi[i]=sum[i]=suf[i]=0;
   tot=0;
}

void work()
{
   Clear();
   scanf("%d%d",&n,&Q);
   for(int i=1;i<=n;i++)scanf("%d",&a[i]);
   for(int i=n;i>=1;i--)a[i]-=a[i-1];
   a[1]=0;
   for(int i=2;i<=n;i++)tot+=Max(a[i],0);

   build(1,n,1);
   int flag,l,r,c;
   while(Q--){
      scanf("%d",&flag);
      if(!flag){
         scanf("%d%d%d",&l,&r,&c);
         if(l>1){
            tot-=Max(a[l],0);
            a[l]+=c;
            tot+=Max(a[l],0);
            ins(1,n,1,l);
         }

         if(r<n){
            tot-=Max(a[r+1],0);
            a[r+1]-=c;
            tot+=Max(a[r+1],0);
            ins(1,n,1,r+1);
         }
      }
      else printf("%lld %d\n",tot,tr[1]<<1);
   }
}

int main(){
   int T;cin>>T;
   while(T--)work();
   return 0;
}

posted @ 2017-11-03 20:05  Hxymmm  阅读(257)  评论(0编辑  收藏  举报