seq

【from new_dtoj 3973: seq】
题目描述
小y 的男朋友送给小y 一个数列ai{a_i},并且***难小y 要她维护这个序列。
具体而言,小y 的男朋友要求小y 完成两个操作:

  1. 修改数列中的一个数
  2. pip_i表示maxj=1iajmax_{j=1}^ia_j,求出i=1npi\sum_{i=1}^{n}p_i

小y 不会做,于是向你求助。
输入
第一行一个数n表示数列长度。
第二行n个由空格隔开的数表示数列a。
第三行一个数m表示修改数。
接下来m行,每行两个数pos,value,表示把aposa_{pos}改成value。
输出
输出m行,每行一个数,表示对于每次修改后的i=1npi\sum_{i=1}^{n}p_i
样例输入
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]这个k节点上面的答案,LsLsRsRs是其左右儿子
考虑到LsLs上的答案不会被RsRs影响,但是RsRs的答案可能被LsLs影响,所以LsLs上的答案可以直接赋值到kk上,所以就只要算出RsRs的答案
LcLcRcRcRsRs的左右儿子,ppLsLs区间最大值,这里进行分类

  1. p>=Rsmaxp>=Rs_{max}
    那么这个区间就被覆盖了,于是RsRs的答案就是pRsp*Rs区间长度
  2. p>=Lcmaxp>=Lc_{max}
    那么LcLc就会被完全覆盖,于是我们把问题转化成其子问题,求出RcRc的答案,那么RsRs的答案就是pLcp*Lc区间长度+RcRc的答案
  3. 剩下
    RcRc不会被pp影响到,所以可以算出RcRc的答案就是用RsRs的答案-LcLc的答案,然后往LcLc递归,求出LcLc的答案,那么RsRs的答案就是LcLc的答案+RcRc的答案

修改的话就是单点修改,然后合并过程也是一样的
具体见代码

#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;
}
posted @ 2018-10-20 17:29  xjqxjq  阅读(244)  评论(0编辑  收藏  举报