浅谈线段树
线段树详解(非递归实现)
线段树与树状数组的区别,作者:闵梓轩
demo
/***********************************************/
int n,a[maxn+2],m;
struct node{
int l,r;
int h;
}tree[4*maxn+5];
void build(int l,int r,int k)
{
tree[k].l=l;tree[k].r=r;tree[k].h=0;
if(l!=r)//未到叶子节点
{
int mid=(l+r)/2;
build(l,mid,2*k);//左孩子
build(mid+1,r,2*k+1);//右
}
}
void update(int l,int r,int k,int p)//区间修改,从头遍历,k记录此时遍历位置
{
int L,R;
if(r<tree[k].l || l>tree[k].r) return ;
else if(l<=tree[k].l && r>=tree[k].r)//修改区间全包含tree
{
L=tree[k].l;
R=tree[k].r;
}
else if(l>tree[k].l && r<=tree[k].r)//全被包含
{
L=l;
R=r;
}
else if(l<tree[k].l && r<tree[k].r) //左交
{
L=tree[k].l;
R=r;
}
else if(r>tree[k].r && l>tree[k].l)//右交
{
L=l;
R=tree[k].r;
}
tree[k].h+=(abs(R-L)+1)*p;
if(tree[k].l==tree[k].r) return ;
update(l,r,2*k,p);
update(l,r,2*k+1,p);
}
void update1(int x,int k,int p)//单点修改
{
if(x>=tree[k].l && x<=tree[k].r)
{
tree[k].h+=p;
int mid=(tree[k].l+tree[k].r)/2;
if(x<=mid) update1(x,2*k,p);
else update1(x,2*k+1,p);
}
if(tree[k].r==tree[k].l) return ;
}
void ask1(int k,int p)//单点查询
{
if(tree[k].l==tree[k].r && tree[k].r==p) printf("%d
",tree[k].h);
else {
int mid=(tree[k].l+tree[k].r)/2;
if(p<=mid) ask1(2*k,p);
else ask1(2*k+1,p);
}
}
int ans=0;
void ask(int l,int r,int k)//区间查询
{
if(tree[k].l>=l && tree[k].r<=r) ans=max(ans,tree[k].h);
else
{
int mid=(tree[k].l+tree[k].r)/2;
if(!(l>mid || r<tree[k].l)) ask(l,r,2*k);
if(!(r<mid+1 || l>tree[k].r)) ask(l,r,2*k+1);
}
}
int main()
{
c_2(n,m);
build(1,n,1);
for(int i=1;i<=n;i++) cin>>a[i],update1(i,1,a[i]);//此处a[i]可以在build时就加入,更高效
for(int i=1;i<=m;i++)
{
int op,x,y,k;
cin>>op;
if(op==1)
{
cin>>x>>y>>k;
update(x,y,1,k);
}
else
{
cin>>x;
ans=0;
ask1(1,x);
//cout<<ans<<endl;
}
//update(l,r,1,1);
}
//cout<<tree[1].h<<endl;
return 0;
}