#include<stdio.h>
#include<iostream>
using namespace std;
int n,f[400010],q,x,y,z;
struct tree{
int left,right,value;//每个树节点所表示范围的左l右r和 叶节点的值 或 非叶节点的 flag<加的数>
}a[400010];
void build(int l,int r,int cur){//构建线段树
a[cur].left=l;//记录该点的左右起止范围
a[cur].right=r;
if(l==r){//如果是叶节点
f[l]=cur;//f数组记录某个区间内只有一个值<叶节点>的位置<树上的节点位置cur>
return ;
}
build(l,(l+r)/2,cur*2);//递归左子树
build((l+r)/2+1,r,cur*2+1);//递归右子树
return ;
}
void add(int l,int r,int cur,int c){//[l,r]区间内加c,从树的根节点i=1 开始搜索
if(a[cur].left==l&&a[cur].right==r){//找到目标区间,区间内加c
a[cur].value+=c; return ;
}
//下面讨论区间[l,r]与节点i区间的关系,并进行判断递归
int mid=(a[cur].left+a[cur].right)/2;//cur点的中点
if(r<=mid&&l<=mid) add(l,r,cur*2,c);//满足该情况下.此时[l,r]都在i节点区间的左半部分,递归i节点的左子树
if(mid+1<=l&&mid+1<=r) add(l,r,(cur*2)+1,c);//满足该情况下.此时[l,r]都在i节点区间的右半部分,递归i节点的右子树
if(l<=mid&&mid+1<=r){//满足该情况下.此时[l,r]横跨i节点区间,i节点的左右子树都要递归
add(l,mid,cur*2,c);
add(mid+1,r,(cur*2)+1,c);
}
}
int ffind(int cur){//从叶节点开始从下往上搜索,累加搜索到的节点的.value的值,ffind(i/2)表示搜索i节点的父节点,直到根节点
if(cur==0) return 0;
return a[cur].value+ffind(cur/2);
}
int main(){
freopen("1081.in","r",stdin);
freopen("1081.out","w",stdout);
scanf("%d",&n);
build(1,n,1);//构建线段树
for(int i=1;i<=n;i++){
scanf("%d",&x);//读入
a[f[i]].value=x;//每个点递归到最后都会在f内有值
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
int k=0;
scanf("%d",&k);
if(k==1){
scanf("%d%d%d",&x,&y,&z);
add(x,y,1,z);//[x,y]区间内加 z 从树的根节点i=1 开始搜索
}
if(k==2){
scanf("%d",&x);
printf("%d",ffind(f[x]));//递归以x点在线段树上的节点位置作为开始坐标
}
}
return 0;
}
题解:详见注释。