线段树单点修改,区间查询的模板题

1547:【 例 1】区间和 (信息学一本通网站)

时间限制: 1000 ms         内存限制: 524288 KB
提交数: 1175     通过数: 318 

【题目描述】

给定一数列,规定有两种操作,一是修改某个元素,二是求区间的连续和。

【输入】

输入数据第一行包含两个正整数n,m(n≤100000,m≤500000),以下是m行,

每行有三个正整数k,a,b(k=0或1,a,b≤n).k=0时表示将a处数字加上b,k=1时表示询问区间[a,b]内所有数的和。

【输出】

对于每个询问输出对应的答案。

【输入样例】

10 20
0 1 10
1 1 4
0 6 6
1 4 10
1 8 9
1 4 9
0 10 2
1 1 8
0 2 10
1 3 9
0 7 8
0 3 10
0 1 1
1 3 8
1 6 9
0 5 5
1 1 8
0 4 2
1 2 8
0 1 1

【输出样例】

10
6
0
6
16
6
24
14
50
41

模板题

#include
#define N 100000+5
#define LL long long
using namespace std;
int n,m,v;
LL a[N],t[4*N];//线段树必须为4*N 空间

//传入的参数为 k当前需要建立的结点;l当前需要建立的左端点;r当前需要建立的右端点
void build(int k,int L,int R) {
	if (L==R) t[k]=a[L];//当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
	else {
		int mid = (L+R)/2;
		build(k*2,L,mid);
		build(k*2+1,mid+1,R);
		t[k] = t[k*2] + t[k*2+1];//递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
	}
}

//单点修改:
//k、l、r为当前更新到的结点、左右端点,
//x为需要修改的叶子结点左端点
//y为需要修改成的值;
void update(int k,int l,int r,int x,int y) {
	if(l==r) {
		a[x]+=y;
		t[k]+=y;
		return;
	}
	int mid=(l+r)/2;
	if (x>=l&&x<=mid) update(k*2,l,mid,x,y);
	else update(k*2+1,mid+1,r,x,y);
	t[k]=t[k*2]+t[k*2+1];
}

LL query(int k,int l,int r,int x,int y) { //x、y为需要查询的区间左右端点
	//若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值
	//(如求和时返回0,求最大值时返回-1等)
	if (x>r||y=r) return t[k];
	int mid=(l+r)/2;
	//p1为查询左儿子结点得到的信息,p2为查询右儿子结点得到的信息
	LL p1=query(k*2,l,mid,x,y);
	LL p2=query(k*2+1,mid+1,r,x,y);
	return p1+p2;综合两个儿子结点的信息并返回return p1+p2

}

int main() {
	scanf("%d%d",&n,&m);
	//build(1,1,n);
	while(m--) {
		int k,a,b;
		scanf("%d%d%d",&k,&a,&b);
		if (k==0) {
			update(1,1,n,a,b);
		} else {
			LL ans=query(1,1,n,a,b);
			printf("%lld\n",ans);
		}
	}

	return 0;
}

 

你可能感兴趣的:(数据结构--线段树)