原题链接:1264. 动态求连续区间和 - AcWing题库

题意:一个数组,两种操作,求区间和或改某个数

思路

数组是动态变化的,前缀和不适用

同样要预处理来减小时间复杂度,要求的是一个区间的和,且要保证每个数的改变要影响到预处理的区间和,如果前缀和每次都是 ,用树状数组可以实现二分,即

最高为的复杂度

实际上使用了线段树的模板

实现

#include <iostream>
#include <algorithm>
#include <cstring>
 
using namespace std;
 
const int N = 100010;
 
int n, m;
int w[N]; //记录初始数组
 
struct Node{
    int l, r;
    int sum;
}tr[4 * N];
//四倍空间
 
 
//数组前面反而是根节点
void push_up(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
 
 
void build(int u, int l, int r)
{
    //二分到最后是叶节点
    if(l == r) tr[u] = {l, r, w[r]};
    else
    {
        //二分存下所有
        tr[u] = {l, r};
        
        int mid = (l + r) >> 1;
        //左边构建
        build(u << 1, l, mid);
        //右边构建
        build(u << 1 | 1, mid + 1, r);
        
        //建完更新结点
        push_up(u);
    }
}
 
int query(int u, int l, int r)
{
    //如果左右已经完全被包含了,那就计算返回结果
    if(l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
    
    //否则递归分区域计算,只要有交集,就不断地分,一直到分出来的区域被包含
    int mid = (tr[u].l + tr[u].r) >> 1;
    
    int sum = 0;
    //会分出多个被包含的不重复的区域,所以每次累加,最后返回sum
    if(mid >= l) sum += query(u << 1, l, r);
    
    if(r >= mid + 1) sum += query(u << 1 | 1, l, r);
    
    return sum;
}
 
 
void modify(int u, int x, int y)
{
    //叶子节点
    if(tr[u].l == tr[u].r) tr[u].sum += y;
    else
    {
        //在左边改左节点,在右边就改右边
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(x <= mid) modify(u << 1, x, y);
        else modify(u << 1 | 1, x, y);
        
        //改完更新
        push_up(u);
    }
}
 
 
int main()
{
    cin >> n >> m;
    
    for(int i = 1; i <= n; i ++) cin >> w[i];
    //初始化
    build(1, 1, n);
    
    while(m --)
    {
        int k, a, b;
        
        cin >> k >> a >> b;
        
        if(!k) cout << query(1, a, b) << endl;
        else modify(1, a, b);
    }
    
    return 0;
}