算法思路
该算法,主要有四种基本函数
1.pushup(u):用子节点信息来更新当前节点信息(把信息往上传递)2、build(u,l,r):在一段区间上初始化线段树,其中u表示根结点,l表示左边界,r表示右边界
3、query(u,l,r):查询某段区间的和,其中u表示根结点,l表示左边界,r表示右边界
4、modify(u,x,v):修改操作,在u结点中,x位置加上v
线段数图解
修改操作
查询操作
模版题
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
int w[N];
struct Node
{
int l, r;
int sum;
}tr[N * 4];
//这里一般是数据的4倍
void pushup(int u)
{
// u << 1 | 1 --> 2x + 1
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};
//向下取整分区间, [l, mid] [mid + 1, r],分区间
int mid = (l + r) >> 1;
build(u << 1, l , mid), build(u << 1 | 1, mid + 1 , r);
//区间分了,节点信息要更新
pushup(u);
}
}
int query(int u, int l, int r)
{
//序列完全包含要求的区间
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
int mid = (tr[u].l + tr[u].r) >> 1;
int sum = 0;
//区间 [l, mid] [mid + 1, r]
//注意:此处代码写法 并且query区间始终是l和r
//并且此处不能写else if
if(l <= mid) sum = query(u << 1, l, r); //与左区间右交集
if(r > mid) sum += query(u << 1 | 1, l, r);
return sum;
}
//修改某个数 (sum加上某个数)
void modify(int u, int x ,int v)
{
//就剩一个数,这个数组的sum加上v
if(tr[u].l == tr[u].r) tr[u].sum += v;
else
{
int mid = (tr[u].l + tr[u].r) >> 1;
//二叉树
//这个数小于mid,递归左子树
if(x <= mid) modify(u << 1, x, v);
else if(x > mid) modify(u << 1 | 1, x, v);
//数改变,更新节点信息
pushup(u);
}
}
int n, m;
int main()
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
//初始化线段树, 根节点1开始,节点从1到n
build(1, 1, n);
while(m--)
{
int k, a, b;
scanf("%d %d %d", &k, &a, &b);
if(k == 0) printf("%d\n", query(1, a, b));
else if(k = 1) modify(1, a, b);
}
return 0;
}