“学习本无底,前进莫徬徨。” 秋实大哥对一旁玩手机的学弟说道。
秋实大哥是一个爱学习的人,今天他刚刚学习了线段树这个数据结构。
为了检验自己的掌握程度,秋实大哥给自己出了一个题,同时邀请大家一起来作。
秋实大哥的题目要求你维护一个序列,支持两种操作:一种是修改某一个元素的值;一种是询问一段区间的和。
Input
第一行包含一个整数 n ,表示序列的长度。
接下来一行包含 n 个整数 ai ,表示序列初始的元素。
接下来一行包含一个整数 m ,表示操作数。
接下来 m 行,每行是以下两种操作之一:
1 x v : 表示将第x个元素的值改为v 2 l r : 表示询问[l,r]这个区间的元素和
1≤n,m,v,ai≤100000 , 1≤l≤r≤n 。
Output
对于每一个 2 l r 操作,输出一个整数占一行,表示对应的答案。
Sample input and output
Sample Input | Sample Output |
---|---|
3 1 2 3 3 2 1 2 1 1 5 2 1 2 | 3 7 |
线段树。更新点,询问区间。
节点记录区间段、区间元素总和。根据初始值建树。更新点时更新包含点的所有线段节点的sum值。询问时向下递归。
#include <iostream>
#include <cstdio>
#define lid (id << 1)
#define rid (id << 1 | 1)
using namespace std;
const int N=100005;
struct node
{
int l,r;
long long sum;
}tr[N * 4];
int a[N];
void push_up(int id)
{
tr[id].sum = tr[lid].sum + tr[rid].sum;
}
void build(int id, int l,int r)
{
tr[id].l = l; tr[id].r = r;
if(l == r)
{
tr[id].sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(lid, l, mid);
build(rid, mid + 1, r);
push_up(id);
}
void updata(int id,int x,int v)
{
if(tr[id].l == tr[id].r){
tr[id].sum = v;
return;
}
int mid = (tr[id].l + tr[id].r) >> 1;
updata(x <= mid ? lid : rid, x, v);
push_up(id);
}
long long query(int id, int l, int r)
{
if(tr[id].l == l && tr[id].r == r)
return tr[id].sum;
int mid = (tr[id].l + tr[id].r) >> 1;
if(r <= mid) return query(lid, l, r);
if(l > mid) return query(rid, l, r);
return query(lid, l, mid)+query(rid, mid + 1,r);
}
int main()
{
int n,m;
int p,x,y;
scanf("%d",&n);
for(int i = 1;i <= n; i ++)
scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
while(m --)
{
scanf("%d%d%d",&p,&x,&y);
if(p == 1)
updata(1, x, y);
else
printf("%lld\n",query(1,x,y));
}
return 0;
}