线段树---单点修改

思路:

线段树,每个节点都被模拟成一条线段,负责维护这条线段(下面成为区间)从从左端点到有端点这一部分的信息。

大致思路是这样的:一个父节点负责维护一块大区间的信息,他有两个左右子节点,编号为分别负责维护父节点的左一半区间和右一半区间。

这个图是维护区间最大值的线段树.

数据结构:

根节点编号为1。编号为rt的节点,维护区间是[l,r];左儿子编号为rt*2,维护[l,(r+l)/2];右儿子编号为rt*2+1,维护[(r+l)/2+1,r]。

线段树是一颗完全二叉树,维护[1,n]序列的线段树右2n-1个节点,所以线段树要开四倍空间。

 

模板:

建树

int a[N],sum[N*4];
void init(){
    memset(a,0,sizeof(a));
    memset(sum,0,sizeof(sum));
}
void push_up(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1]; //父区间点的子区间之和
}
void bulid(int rt,int l,int r){  //从根节点的编号,1开始,自上而下建树
    if(l==r){      //递归边界,达到叶节点
        sum[rt]=a[l];    
        return ;
    }
    int mid=(l+r)>>1;
    bulid(rt<<1,l,mid);  //左
    bulid(rt<<1|1,mid+1,r);  //右
    push_up(rt);  //回溯:子节点建成,组成父节点
}

 

单点更新(增值),查询区间和

 1 void update(int rt,int l,int r,int p,int v){  
 2     if(l==r){    //到达修改区间的叶节点
 3         sum[rt]+=v;
 4         return ;
 5     }
 6     int mid=(l+r)>>1;
 7     if(p<=mid)       //向左更新
 8         update(rt<<1,l,mid,p,v);
 9     else if(p>mid)    //向右更新
10         update(rt<<1|1,mid+1,r,p,v);
11     push_up(rt);    //子节点更新完成,更新父节点
12 }
13 int  query(int rt,int l,int r,int ll,int rr){
14     if(ll<=l&&r<=rr){  //查询区间完全包含当前区间
15         return sum[rt];
16     }
17     int mid=(l+r)>>1;
18     int res=0;
19     if(ll<=mid) res+=query(rt<<1,l,mid,ll,rr);  //访问查询区间在当前左区间的部分
20     if(rr>mid)    res+=query(rt<<1|1,mid+1,r,ll,rr);
21     return res;
22 }

单点改值

即第3行改成 : sum[rt]=v; query()中的v ,代表a[p]=v;

 

单点增值 求区间最大数

 1 const int N=5e4+10;
 2 int a[N],MAX[N*4];
 3 void init(){
 4     memset(a,0,sizeof(a));
 5     memset(MAX,0,sizeof(MAX));
 6 }
 7 void push_up(int rt){
 8     MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
 9 }
10 void bulid(int rt,int l,int r){
11     if(l==r){
12         MAX[rt]=a[l];
13         return ;
14     }
15     int mid=(l+r)>>1;
16     bulid(rt<<1,l,mid);
17     bulid(rt<<1|1,mid+1,r);
18     push_up(rt);
19 }
20 void update(int rt,int l,int r,int p,int v){ 
21     if(l==r){
22         MAX[rt]+=v;
23         return ;
24     }
25     int mid=(l+r)>>1;
26     if(p<=mid) 
27         update(rt<<1,l,mid,p,v);
28     else if(p>mid)
29         update(rt<<1|1,mid+1,r,p,v);
30     push_up(rt);
31 }
32 int  query(int rt,int l,int r,int ll,int rr){
33     if(ll<=l&&r<=rr){
34         return MAX[rt];
35     }
36     int mid=(l+r)>>1;
37     int res=0;
38     if(ll<=mid) res=max(res,query(rt<<1,l,mid,ll,rr));
39     if(rr>mid)    res=max(res,query(rt<<1|1,mid+1,r,ll,rr));
40     return res;
41 }

 

区间改值 :第16行 改为MAX[rt]=v;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值