线段树

线段树是一种可以根据子问题解决父问题的数据结构

比如说

求一段区间的和(\(\sum_{i=L}^Ra_i=\sum_{i=L}^Ma_i+\sum_{i=M+1}^Ra_i\quad ,L\leq M<R\)

求一段区间的最大值(\(\max_{i=L}^Ra_i=\max(\max_{i=L}^Ma_i,\max_{i=M+1}^Ra_i)\quad ,L\leq M<R\)

可以用线段树维护的问题必须满足 区间加法 ,否则是不可能将大问题划分成子问题来解决的。

例题:

P3372 【模板】线段树 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

243. 一个简单的整数问题2 - AcWing题库

板子:

struct point{
    int l,r;
    i64 sum,add;
}tr[N*4];
void pushup(int u){
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u){
    auto &root=tr[u];
    auto &left=tr[u<<1];
    auto &right=tr[u<<1|1];
    if(root.add){
        left.add+=root.add;left.sum+=(i64)(left.r-left.l+1)*root.add;
        right.add+=root.add;right.sum+=(i64)(right.r-right.l+1)*root.add;
        root.add=0;
    }
}
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r,a[l],0};
    }
    else{
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int l,int r,int d){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].sum+=(i64)(tr[u].r-tr[u].l+1)*d;
        tr[u].add+=d;
    }
    else{
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid)modify(u<<1,l,r,d);
        if(r>mid)modify(u<<1|1,l,r,d);
        pushup(u);
    }
}
i64 query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum;
    pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    i64 sum=0;
    if(l<=mid)sum=query(u<<1,l,r);
    if(r>mid)sum+=query(u<<1|1,l,r);
    return sum;
}

先鸽了以后再补充

posted @ 2023-01-20 12:28  liangqianxing  阅读(27)  评论(0)    收藏  举报