To_Heart—题解——内需消费
题解
首先,我们先假设这道题不需要修改物价,那么我们如何找到最好的情况呢?
差分。如下数列:
1 4 3 5 2
很容易观察出,在第一个商店到第二个商店中,我们最多可以赚3元,在第一个商店进货,第二个商店卖出。
但是在第二个商店到第三个商店的途中,我们不能赚钱。因为第二个商店的价格比第三个商店的价格的价格大,所以最优的情况是不进行买卖操作。
所以我们第一个商店到第三个商店最多能赚多少呢?即是在第一个商店买,第二个商店卖,在第三个商店不进行操作。
那么对于第一个商店到第四个商店,最多赚4元。但4=3+0+1,即选择在第一个商店买,第二个商店又买又卖,第三个商店不进行操作,第四个商店又卖;
所以就是差分了。
定义a[i],存放每个商店的价格;
定义sum[i],表示由第i到i+1最多可以赚的钱数;
sum[i]=max(0,a[i+1]-a[i]);
因为如果a[i]>a[i+1],那么最优操作是不进行买卖,也就是赚0元。
最后的答案就是求差分数组的和了。
值得注意的是,在这道题中,从i走到j和从j走到i是不一样的意思的,所以需要两个差分数组;
对于差分数组,可以用线段树维护。
现在我们来想一下如何进行改变值的操作。
设:a[i]改变了,只会影响 a [ i ] − a [ i + 1 ] , a [ i + 1 ] − a [ i ] , a [ i ] − a [ i − 1 ] a[i] - a[i+1], a[i+1] - a[i],a[i] - a[i-1] a[i]−a[i+1],a[i+1]−a[i],a[i]−a[i−1]以及 a [ i − 1 ] − a [ i ] a[i-1] - a[i] a[i−1]−a[i]的值,所以我们只需要改变 i − 1 , i , i + 1 i-1,i,i+1 i−1,i,i+1的差分值就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll int
#define L(a) t[a].val_to_l
#define R(a) t[a].val_to_r
struct Segment_Tree{
int l,r;
ll val_to_l;
ll val_to_r;
}t[4000005];
int n,m;
ll a[1000005];
void Build_Tree(int q,int l,int r){
t[q].l=l;
t[q].r=r;
if(l==r){
L(q)=max(0,a[l]-a[l-1]);
R(q)=max(0,a[l]-a[l+1]);
return;
}
int mid=(l+r)>>1;
Build_Tree(q*2,l,mid);
Build_Tree(q*2+1,mid+1,r);
L(q)=L(q*2)+L(q*2+1);
R(q)=R(q*2)+R(q*2+1);
}
void Change_Tree(int q,int x){
if(x>n||x<1) return ;
if(t[q].l==t[q].r){
L(q)=max(0,a[t[q].l]-a[t[q].l-1]);
R(q)=max(0,a[t[q].l]-a[t[q].l+1]);
return ;
}
int mid=(t[q].r+t[q].l)>>1;
if(x<=mid){
Change_Tree(q*2,x);
}
else{
Change_Tree(q*2+1,x);
}
L(q)=L(q*2)+L(q*2+1);
R(q)=R(q*2)+R(q*2+1);
}
ll Find_Tree(int p,int l,int r,int op){
ll ans=0;
if(t[p].l>=l&&t[p].r<=r){
return op?R(p):L(p);
}
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid){
ans+=Find_Tree(p*2,l,r,op);
}
if(mid<r){
ans+=Find_Tree(p*2+1,l,r,op);
}
return ans;
}
void Put(){
for(int i=1;i<=4*n;i++){
printf("t[%d] %d %d %d %d\n",i,t[i].l,t[i].r,L(i),R(i));
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
Build_Tree(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op&1){
if(x==y){ printf("0\n");}
else if(x>y)
printf("%d\n",Find_Tree(1,y,x-1,1));
else
printf("%d\n",Find_Tree(1,x+1,y,0));
}
else {
a[x]=y;
Change_Tree(1,x);
Change_Tree(1,x-1);
Change_Tree(1,x+1);
}
// Put();
}
return 0;
}