传送门:线段树练习
线段树 区间修改 + 单点查询
题目描述
Description
给你N个数,有两种操作
1:给区间[a,b]的所有数都增加X
2:询问第i个数是什么?
输入描述
Input Description
第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是1,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是2,后面跟1个整数i, 表示询问第i个位置的数是多少。
输出描述
Output Description
对于每个询问输出一行一个答案
样例输入
Sample Input
3
1
2
3
2
1 2 3 2
2 3
样例输出
Sample Output
5
数据范围及提示
Data Size & Hint
数据范围
1<=n<=100000
1<=q<=100000
区间修改 + 单点查询
代码如下
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,p,x,y,z,ans;
struct Tree{
int l;
int r;
int w;
int f;
}tree[400100];
void build(int l,int r,int k)
{
tree[k].l = l;
tree[k].r = r;
if(l == r)
{
scanf("%d",&tree[k].w);
return ;
}
int m = (tree[k].l + tree[k].r) >>1;
build(l,m,k<<1);
build(m+1,r,k<<1|1);
tree[k].w = tree[k<<1].w + tree[k<<1|1].w;
}
void down(int k)
{
tree[k<<1].f += tree[k].f;
tree[k<<1|1].f += tree[k].f;
tree[k<<1].w += (tree[k<<1].r - tree[k<<1].l + 1 )*tree[k].f;
tree[k<<1|1].w += (tree[k<<1|1].r - tree[k<<1|1].l + 1 ) * tree[k].f;
tree[k].f = 0;
}
void add(int k)
{
if(tree[k].l>=x&&tree[k].r<=y)
{
tree[k].w += (tree[k].r - tree[k].l +1) *z;
tree[k].f += z;
return ;
}
if(tree[k].f) down(k);
int m = (tree[k].l + tree[k].r)>>1;
if(x<=m) add(k<<1);
if(y>m) add(k<<1|1);
tree[k].w = tree[k<<1].w + tree[k<<1|1].w;
}
void ask(int k)
{
if(tree[k].l == tree[k].r)
{
ans = tree[k].w;
return ;
}
if(tree[k].f) down(k);
int m = (tree[k].l + tree[k].r )>> 1;
if(x<=m) ask(k<<1);
else ask(k<<1|1);
}
int main()
{
scanf("%d",&n);
build(1,n,1);
scanf("%d",&m);
while(m--)
{
scanf("%d",&p);
if(p == 1)
{
scanf("%d%d%d",&x,&y,&z);
add(1);
}
else {
scanf("%d",&x);
ask(1);
printf("%d\n",ans);
}
}
return 0;
}