线段树模板

 ̄綄美尐妖づ 提交于 2020-02-04 22:19:32

线段树模板

单点更新+区间查询

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#define ll long long

#define l(p) t[p].l //区间左端点
#define r(p) t[p].r //区间右端点
#define mid (l(p)+r(p))/2
#define sum(p) t[p].sum
#define lp p<<1  //左孩子
#define rp (p<<1)|1 //右孩子
using namespace std;
const int maxN = 2e5+10;
int a[maxN];
struct Node{
    int l,r,sum;
}t[maxN*4];
void build(int p,int l, int r){
    l(p)=l;r(p)=r;
    if(l==r){
        sum(p)=a[l];
        return;
    }
    build(lp, l, mid);
    build(rp,mid+1,r);
    sum(p)=sum(lp)+sum(rp);
}

void change(int p,int x,int v){
    if(l(p)==r(p)){  //直到找到叶节点
        sum(p)=v;
        return;
    }
    if(x<=mid) change(lp, x, v);
    else change(rp, x, v);
    sum(p)=sum(lp)+sum(rp); //这一步不要忘记更新信息
}
int ask(int p,int l,int r){
    if(l<=l(p)&&r>=r(p)) return sum(p);
    int res=0;
    if(l<=mid) res+=sum(lp);
    if(r>mid) res+=sum(rp);
    return res;
}
int n,m;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1, 1, n); //不要忘记建树
    while(m--){
        char s[10];int l,r,x,v;
        scanf("%s",s);
        if(s[0]=='C'){
            scanf("%d%d",&x,&v);
            change(1, x, v);
        }else{
            scanf("%d%d",&l,&r);
            printf("%d\n",ask(1, l, r));
        }
    }
}

区间修改(lazy tag)

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#define ll long long

#define l(p) t[p].l //区间左端点
#define r(p) t[p].r //区间右端点
#define mid (l(p)+r(p))/2
#define sum(p) t[p].sum
#define lp p<<1  //左孩子
#define rp (p<<1)|1 //右孩子
#define tag(p) t[p].tag
using namespace std;
const int maxN = 2e5+10;
int a[maxN];
struct Node{
    int l,r,sum;
    int tag=1;
}t[maxN*4];
void build(int p,int l, int r){
    l(p)=l;r(p)=r;
    if(l==r){
        sum(p)=a[l];
        return;
    }
    build(lp, l, mid);
    build(rp,mid+1,r);
    sum(p)=sum(lp)+sum(rp);
}
void putdown(int p){
    if(tag(p)!=1){
        //更新左右节点
        sum(lp)*=tag(p);
        sum(rp)*=tag(p);
        //左右节点打上延迟标记
        tag(lp)=2*tag(p);
        tag(rp)=2*tag(p);
        tag(p)=1;  //父节点标记删除
    }
}

void change(int p,int l,int r){
    if(l<=l(p)&& r>=r(p)){
        sum(p)*=2;
        tag(p)*=2;
        return;
    }
    putdown(p); //最好写
    if(l<=mid) change(lp, l, r);
    if(r>mid) change(rp,l,r);
    sum(p)=sum(lp)+sum(rp); //这一步不要忘记更新信息
}
int ask(int p,int l,int r){
    if(l<=l(p)&&r>=r(p)) return sum(p);
    putdown(p); //自上而下的访问信息,这里必须下穿标记
    int res=0;
    if(l<=mid) res+=ask(lp, l, r);
    if(r>mid) res+=ask(rp, l, r);
    return res;
}
int n,m;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1, 1, n); //不要忘记建树
    while(m--){
        char s[10];int l,r;
        scanf("%s%d%d",s,&l,&r);
        if(s[0]=='C'){
            change(1,l,r);
        }else{
            printf("%d\n",ask(1, l, r));
        }
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!