Gracekite's Homepage

Back

题目描述#

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 。
  2. 求出某区间每一个数的和。

输入格式#

第一行包含两个整数 ,分别表示该数列数字的个数和操作的总个数。

第二行包含 个用空格分隔的整数,其中第 个数字表示数列第 项的初始值。

接下来 行每行包含 或 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 内每个数加上 。
  2. 2 x y:输出区间 内每个数的和。

输出格式#

输出包含若干行整数,即为所有操作 2 的结果。

样例 #1#

样例输入 #1#

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
plaintext

样例输出 #1#

11
8
20
plaintext

提示#

对于 的数据:,。
对于 的数据:,。
对于 的数据:。

保证任意时刻数列中任意元素的和在 内。

【样例解释】

{% raw %}

{% endraw %}

建树#

void build(int pos,int l,int r){
    tree[pos].l=l,tree[pos].r=r;
    if(l==r) {tree[pos].val=read()%mod;return;}
    int mid=(l+r)>>1;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}
cpp

上放#

void pushup(int pos){
    tree[pos].val=(tree[pos<<1].val+tree[pos<<1|1].val)%mod;
}
cpp

下放#

和#

void pushdown(int pos){
    if(tree[pos].lazy){
        tree[pos<<1].val+=tree[pos].lazy*(tree[pos<<1].r-tree[pos<<1].l+1);
        tree[pos<<1|1].val+=tree[pos].lazy*(tree[pos<<1|1].r-tree[pos<<1|1].l+1);
        tree[pos<<1].lazy+=tree[pos].lazy;
        tree[pos<<1|1].lazy+=tree[pos].lazy;
        tree[pos].lazy=0;
    }
    return;
}
cpp

和与积#


更新#

单点更新(加)#

void updatepoint(int pos,int x,int data){
    if(tree[pos].l==x&&tree[pos].r==x) tree[pos].val+=data;
    pushdown(pos);
    int mid=(tree[pos].l+tree[pos].r)>>1;
    if(mid<x) updatepoint(pos<<1|1,x,data);
    else updatepoint(pos<<1,x,data);
    pushup(pos);
}
cpp

区间更新#

和#
void updatarea_add(int pos,int x,int y,int data){
    int l = tree[pos].l,r=tree[pos].r;
    int len=r-l+1,mid=(l+r)>>1;
    if(l>=x&&r<=y){
        tree[pos].val+=len*data;
        tree[pos].lazy+=data;
        return;
    }
    pushdown(pos);
    if(mid>=x) updatarea_add(pos<<1,x,y,data);
    if(mid<y) updatarea_add(pos<<1|1,x,y,data);
    pushup(pos);
}
cpp
积#
void updatearea_acu(int pos,int x,int y,int data){
    int l = tree[pos].l,r=tree[pos].r;
    int mid=(l+r)>>1;
    if(l>=x&&r<=y){
        tree[pos].val=(tree[pos].val*data)%mod;
        tree[pos].lazy=(tree[pos].lazy*data)%mod;
        tree[pos].mu=(tree[pos].mu*data)%mod;
        return;
    }
    pushdown(pos);
    if(mid>=x) updatearea_acu(pos<<1,x,y,data);
    if(mid<y) updatearea_acu(pos<<1|1,x,y,data);
    pushup(pos);
}
cpp

查询#

单点查询#

int querypoint(int pos,int x){
    if(tree[pos].l==x&&tree[pos].r==x) return tree[pos].val;
    pushdown(pos);
    int mid=(tree[pos].l+tree[pos].r)>>1;
    if(mid<x) return querypoint(pos<<1|1,x);
    else return querypoint(pos<<1,x);
}
cpp

区间和查询#

long long queryarea(int x,int y,int pos){
    int l = tree[pos].l,r=tree[pos].r;
    if(x<=l&&r<=y) return tree[pos].val;
    pushdown(pos);
    int mid=(l+r)>>1;
    long long ans=0;
    if(mid>=x) ans=(ans+queryarea(x,y,pos<<1))//%mod;<--按需
    if(mid<y) ans=(ans+queryarea(x,y,pos<<1|1))//%mod;<--按需
    return ans;
}
cpp

{% raw %}

{% endraw %}

{% raw %}

{% endraw %}

{% raw %}

{% endraw %}

{% raw %}

{% endraw %}

#

{% raw %}

{% endraw %}

Segment Tree线段树
https://betteroier.github.io/blog/segment-tree%E7%BA%BF%E6%AE%B5%E6%A0%91
Author Yuxuan Zheng
Published at August 2, 2022