【from new_dtoj 3973: seq】
题目描述
小y 的男朋友送给小y 一个数列
a
i
{a_i}
ai,并且刁难小y 要她维护这个序列。
具体而言,小y 的男朋友要求小y 完成两个操作:
- 修改数列中的一个数
- 设 p i p_i pi表示 m a x j = 1 i a j max_{j=1}^ia_j maxj=1iaj,求出 ∑ i = 1 n p i \sum_{i=1}^{n}p_i ∑i=1npi
小y 不会做,于是向你求助。
输入
第一行一个数n表示数列长度。
第二行n个由空格隔开的数表示数列a。
第三行一个数m表示修改数。
接下来m行,每行两个数pos,value,表示把
a
p
o
s
a_{pos}
apos改成value。
输出
输出m行,每行一个数,表示对于每次修改后的
∑
i
=
1
n
p
i
\sum_{i=1}^{n}p_i
∑i=1npi。
样例输入
10
114 357 904 407 100 624 449 897 115 846
20
5 357
6 350
2 939
9 1182
7 1062
2 3300
4 6867
4 2076
3 8458
9 6575
10 5737
10 338
9 10446
4 7615
2 5686
4 10091
1 6466
6 15551
3 10914
7 3234
样例输出
7703
7703
8565
9051
9297
29814
54783
29814
71078
71078
71078
71078
75054
75054
77440
85605
92737
119327
123429
123429
题解:
这里要先orz Slz Jyc Lhy Pjd Lkw Szm Chm
这些人太强了!!!
(回归正题)考虑线段树,维护区间的最大值和答案
最大值很好合并,问题是怎么合并答案
设我们要合并
[
l
,
r
]
[l,r]
[l,r]这个k节点上面的答案,
L
s
Ls
Ls和
R
s
Rs
Rs是其左右儿子
考虑到
L
s
Ls
Ls上的答案不会被
R
s
Rs
Rs影响,但是
R
s
Rs
Rs的答案可能被
L
s
Ls
Ls影响,所以
L
s
Ls
Ls上的答案可以直接赋值到
k
k
k上,所以就只要算出
R
s
Rs
Rs的答案
设
L
c
Lc
Lc和
R
c
Rc
Rc是
R
s
Rs
Rs的左右儿子,
p
p
p是
L
s
Ls
Ls区间最大值,这里进行分类
-
p
>
=
R
s
m
a
x
p>=Rs_{max}
p>=Rsmax
那么这个区间就被覆盖了,于是 R s Rs Rs的答案就是 p ∗ R s p*Rs p∗Rs区间长度 -
p
>
=
L
c
m
a
x
p>=Lc_{max}
p>=Lcmax
那么 L c Lc Lc就会被完全覆盖,于是我们把问题转化成其子问题,求出 R c Rc Rc的答案,那么 R s Rs Rs的答案就是 p ∗ L c p*Lc p∗Lc区间长度+ R c Rc Rc的答案 - 剩下
故 R c Rc Rc不会被 p p p影响到,所以可以算出 R c Rc Rc的答案就是用 R s Rs Rs的答案- L c Lc Lc的答案,然后往 L c Lc Lc递归,求出 L c Lc Lc的答案,那么 R s Rs Rs的答案就是 L c Lc Lc的答案+ R c Rc Rc的答案
修改的话就是单点修改,然后合并过程也是一样的
具体见代码
#include <cstdio>
#include <algorithm>
#define I inline
#define Ls k<<1
#define Rs Ls|1
#define LL long long
using namespace std;
const int N=3e5+5;int n,m;LL d[N],ax[N*4],s[N*4];
I LL get(LL v,int k,int l,int r){
if (v>=ax[k]) return (r-l+1)*v;
if (l==r) return s[k];
int mid=l+r>>1;
if (v>=ax[Ls]) return (mid-l+1)*v+get(v,Rs,mid+1,r);
else return s[k]-s[Ls]+get(v,Ls,l,mid);
}
I void hb(int k,int l,int r){
ax[k]=max(ax[Ls],ax[Rs]);
int mid=l+r>>1;
s[k]=s[Ls]+get(ax[Ls],Rs,mid+1,r);
}
I void build(int k,int l,int r){
if (l==r){ax[k]=s[k]=d[l];return;}
int mid=l+r>>1;
build(Ls,l,mid);
build(Rs,mid+1,r);
hb(k,l,r);
}
I void change(int k,int x,LL w,int l,int r){
if (l==r){ax[k]=s[k]=w;return;}
int mid=l+r>>1;
if (mid<x) change(Rs,x,w,mid+1,r);
else change(Ls,x,w,l,mid);
hb(k,l,r);
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld",&d[i]);
build(1,1,n);
for (scanf("%d",&m);m--;){
int x;LL y;scanf("%d%lld",&x,&y);
change(1,x,y,1,n);
printf("%lld\n",s[1]);
}
return 0;
}