zoukankan      html  css  js  c++  java
  • 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=1npisum_{i=1}^{n}p_i

    小y 不会做,于是向你求助。
    输入
    第一行一个数n表示数列长度。
    第二行n个由空格隔开的数表示数列a。
    第三行一个数m表示修改数。
    接下来m行,每行两个数pos,value,表示把aposa_{pos}改成value。
    输出
    输出m行,每行一个数,表示对于每次修改后的i=1npisum_{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
    ",s[1]);
        }
        return 0;
    }
    
  • 相关阅读:
    LeetCode: Maximum Product Subarray 解题报告
    LeetCode: Populating Next Right Pointers in Each Node II 解题报告
    LeetCode: Populating Next Right Pointers in Each Node 解题报告
    LeetCode: Word Search 解题报告
    C语言文件操作
    多线程
    C语言函数指针的使用
    进程
    网络编程
    进程间通信——管道通信
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10544726.html
Copyright © 2011-2022 走看看