seq

题目描述

小y 的男朋友送给小y 一个数列{ai},并且刁难小y 要她维护这个序列。
具体而言,小y 的男朋友要求小y 完成两个操作:

  1. 修改数列中的一个数
  2. p i p_i 表示 m a x j = m a x ( a i ) ( i < j ) max_j=max(a_i)(i<j) ,求出 1 n p i ∑_1^np_i
    小y 不会做,于是向你求助。

题解

显然这是一棵线段树,不要问我为什么,显然(个鬼哦)。
如果我们每次维护这个区间的正确的值那么如果碰到一个点高于后面所有的点,然后它掉下来了,后面全部一个一个更新一定会爆炸。所以我们用线段树的常见套路,维护只有这个区间的值,然后考虑合并。
考虑一个函数 p u s h u p ( w , o ) pushup(w,o) 表示一个值 w w 在区间 o o 的左边会对 o o 造成什么影响
大力分讨:

  1. m a x o max_o 大,那么返回区间长度*w
  2. m a x l o max_{lo} 大,那么左边整棵树的值是左区间长度*w+w去更新右区间的值
  3. 3.比 m a x l o max_{lo} 小,那么说明右边区间的值一定是被左边更新的,所以右边的值等于 s u m o s u m l o sum_o-sum_{lo} 再加上w更新左区间的值

代码

#include <bits/stdc++.h>
#define LL long long
#define maxn 300005
#define lo (o<<1)
#define ro (o<<1|1)
#define mid (l+r>>1)
#define MX(a,b) (a>b?a:b)
using namespace std;
LL n,m,a[maxn];
struct NODE{
    LL l,r,mx,sum;
}tr[maxn<<2];
LL pushup(LL w,int o){
    if(tr[o].l==tr[o].r) return max(w,tr[o].sum);
    if(w>tr[o].mx) return (tr[o].r-tr[o].l+1)*w;
    if(w<tr[lo].mx) return pushup(w,lo)+tr[o].sum-tr[lo].sum;
    return (tr[lo].r-tr[lo].l+1)*w+pushup(w,ro);
}
void wh(int o){
    tr[o].sum=tr[lo].sum+pushup(tr[lo].mx,ro);
    tr[o].mx=max(tr[lo].mx,tr[ro].mx);
}
void build(int o,int l,int r){
    tr[o]=(NODE){l,r,0,0};
    if(l==r){tr[o].mx=tr[o].sum=a[l];return;}
    build(lo,l,mid); build(ro,mid+1,r);
    wh(o);
}
void update(int o,int pos,LL w){
    int l=tr[o].l,r=tr[o].r;
    if(pos<l || pos>r) return;
    if(l==r){
        tr[o].sum=tr[o].mx=w;
        return ;
    }
    update(lo,pos,w);
    update(ro,pos,w);
    wh(o);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    build(1,1,n);
    scanf("%d",&m);
    while(m--){
        int pos; LL x;
        scanf("%d%lld",&pos,&x);
        update(1,pos,x);
        printf("%lld\n",tr[1].sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_32461955/article/details/83214752
seq