解题思路
分从左往右和从右往左两个方向差分。
例子:
定义
a
[
i
]
a[i]
a[i],存放每个商店的价格;
定义
s
1
[
i
]
s1[i]
s1[i],表示由第i+1到i最多可以赚的钱数;
s
2
[
i
]
s2[i]
s2[i],表示由第i-1到i最多可以赚的钱数;
s
1
[
i
]
=
m
a
x
(
0
,
a
[
i
+
1
]
−
a
[
i
]
)
;
s1[i]=max(0,a[i+1]-a[i]);
s1[i]=max(0,a[i+1]−a[i]);
s
2
[
i
]
=
m
a
x
(
0
,
a
[
i
−
1
]
−
a
[
i
]
)
;
s2[i]=max(0,a[i-1]-a[i]);
s2[i]=max(0,a[i−1]−a[i]);
(最优操作是不进行买卖,也就是赚0元)
最后的答案就是求差分数组的和了,可以用线段树维护。
如何进行改变值的操作??
设: a [ i ] a[i] a[i]改变了,只会影响 a [ i ] − a [ i + 1 ] , a [ i + 1 ] − a [ i ] , a [ i ] − a [ i − 1 ] , a [ i − 1 ] − a [ i ] a [ i ] − a [ i + 1 ] , a [ i + 1 ] − a [ i ] , a [ i ] − a [ i − 1 ] ,a[i−1]−a[i] a[i]−a[i+1],a[i+1]−a[i],a[i]−a[i−1],a[i−1]−a[i]的值,所以我们只需要改变 i − 1 , i , i + 1 i−1,i,i+1 i−1,i,i+1
代码
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
int n,m,w[100010],opt,p,v;
struct c{
int l,r,s1,s2;
}tree[400010];
void build(int k,int l,int r)
{
tree[k].l=l,tree[k].r=r;
int mid=(l+r)/2;
if(l==r)
{
tree[k].s1=max(0,w[l+1]-w[l]);
tree[k].s2=max(0,w[l-1]-w[l]);
return;
}
build(k*2,l,mid);
build(k*2+1,mid+1,r);
tree[k].s1+=tree[k*2].s1+tree[k*2+1].s1;
tree[k].s2+=tree[k*2].s2+tree[k*2+1].s2;
}
int find(int k,int x,int y,int id)
{
int mid=(tree[k].l+tree[k].r)/2,ans=0;
if(tree[k].l>=x&&tree[k].r<=y)
{
if(id)return tree[k].s2;
else return tree[k].s1;
}
if(x<=mid)ans+=find(k*2,x,y,id);
if(y>mid)ans+=find(k*2+1,x,y,id);
return ans;
}
void change(int k,int x)
{
int mid=(tree[k].l+tree[k].r)/2;
if(tree[k].l==tree[k].r)
{
int l=tree[k].l;
tree[k].s1=max(0,w[l+1]-w[l]);
tree[k].s2=max(0,w[l-1]-w[l]);
return;
}
if(x<=mid)
change(k*2,x);
else change(k*2+1,x);
tree[k].s1=tree[k*2].s1+tree[k*2+1].s1;
tree[k].s2=tree[k*2].s2+tree[k*2+1].s2;
}
int main(){
freopen("trade.in","r",stdin);
freopen("trade.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d",&p,&v);
if(p==v){
printf("0\n");
continue;
}
if(p>v)
printf("%d\n",find(1,v+1,p,1));
else printf("%d\n",find(1,p,v-1,0));
}
if(opt==2)
{
scanf("%d%d",&p,&v);
w[p]=v;
change(1,p);
change(1,p-1);
change(1,p+1);
}
}
}