线段树模板

这一部分的功能和树状数组一样,这里是树状数组的模板
除了求和之外,还能解决区间最小最大值,区间染色

1 单点修改,区间查询

P3374 【模板】树状数组 1

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 10;
struct node{
    int l,r;
    int sum;
}tree[maxn * 4];
int n,m,a[maxn];

void build(int i,int l,int r){
    tree[i].l = l; tree[i].r = r;
    if(l==r){
        tree[i].sum = a[l];
        return;
    }
    int mid = (l + r)/ 2;
    build(i * 2,l,mid);
    build(i * 2 + 1,mid + 1,r);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}
//区间查询
int search(int i,int l,int r){
    //这个区间被完全包括在目标区间里面,返回这个区间的值
    if(tree[i].l >= l && tree[i].r <= r)
        return tree[i].sum;
    //这个区间和目标区间不相干
    if(tree[i].l > r || tree[i].r < l)
        return 0;
    int s = 0;
    //这个区间的左儿子和目标区间有交集
    if(tree[i * 2].r >= l)
        s += search(i * 2,l,r);
    //这个区间的右儿子和目标区间有交集
    if(tree[i * 2 + 1].l <= r)
        s += search(i * 2 + 1,l,r);
    return s;
}

//单点修改
 void add(int i ,int dis,int k){
    //如果是叶子节点,则说明找到了
    if(tree[i].l == tree[i].r){
        tree[i].sum += k;
        return;
    }
    if(dis <= tree[i * 2].r)
        add(i * 2,dis,k);
    else add(i * 2 + 1,dis,k);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;

    return;
}
signed main(){
    //freopen("in","r",stdin);
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    build(1,1,n);
    while(m--){
        int op,x,y;
        cin >> op >> x >> y;
        if(op == 1) add(1,x,y);
        else cout << search(1,x,y) << endl;
    }
    return 0;
}
View Code

2 区间修改,单点查询

P3368 【模板】树状数组 2

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 10;
struct node{
    int l,r;
    int sum;
}tree[maxn * 4];
int n,m,a[maxn];
int ans;
void build(int i,int l,int r){
    tree[i].sum = 0;
    tree[i].l = l; tree[i].r = r;
    if(l==r) return;
    int mid = (l + r)/ 2;
    build(i * 2,l,mid);
    build(i * 2 + 1,mid + 1,r);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}

void search(int i,int dis){
    ans += tree[i].sum;
    if(tree[i].l == tree[i].r)
        return;
    if(dis <= tree[i * 2].r)
        search(i * 2,dis);
    if(dis >= tree[i * 2 + 1].l)
        search(i * 2 + 1,dis);
}
void add(int i ,int l,int r,int k){
    if(tree[i].l >= l && tree[i].r <= r){
        tree[i].sum += k;
        return;
    }
    if(tree[i * 2].r >= l) add(i * 2,l,r,k);
    if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k);
}
signed main(){
    //freopen("in","r",stdin);
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    build(1,1,n);
    while(m--){
        int op,x,y,k;
        cin >> op;
        if(op == 1) {
            cin >> x >> y >> k;
            add(1,x,y,k);
        }
        else {
            cin >> x;
            ans = 0;
            search(1,x);
            cout << ans + a[x] << endl;
        }
    }
    return 0;
}
View Code

 进阶线段树(区间加减)

区间修改 区间查询

区间修改

//把自己的lazytage归零,并且给自己的儿子加上
void pushdown(int i){
    if(tree[i].lz){
        tree[i * 2].lz += tree[i].lz;//左右儿子分别加上父亲的lz
        tree[i * 2 + 1].lz += tree[i].lz;
        int mid = (tree[i].l + tree[i].r)/ 2;
        //左右分别加起来
        tree[i * 2].sum  += tree[i].lz *(mid - tree[i * 2].l + 1);
        tree[i * 2 + 1].sum += tree[i].lz * (tree[i * 2 + 1].r - mid);
        tree[i].lz = 0;//父亲lz归0
    }
    return;
}
View Code

//区间修改(数据更新)
void add(int i ,int l,int r,int k){
    //如果这个区间完全包括在目标区间内
    if(tree[i].l >= l && tree[i].r <= r){
        tree[i].sum += k*(tree[i].r - tree[i].l + 1);
        tree[i].lz += k;//记录lazytage
        return;
    }
    pushdown(i);//向下传递
    if(tree[i * 2].r >= l) add(i * 2,l,r,k);
    if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
    return;
}
View Code

区间查询

int search(int i,int l,int r){
    if(tree[i].l >= l && tree[i].r <= r)
        return tree[i].sum;
    if(tree[i].r < l || tree[i].l > r)
        return 0;
    pushdown(i);
    int s = 0;
    if(tree[i * 2].r >= l) s += search(i * 2,l,r);
    if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r);
    return s;
}
View Code

P3372 【模板】线段树 1

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 10;
struct node{
    int l,r;
    int sum;
    int lz;//lazytage
}tree[maxn * 4];
int n,m,a[maxn];
void build(int i,int l,int r){
    tree[i].lz = 0;
    tree[i].l = l; tree[i].r = r;
    if(l==r){
        tree[i].sum = a[l];
        return;
    }
    int mid = (l + r)/ 2;
    build(i * 2,l,mid);
    build(i * 2 + 1,mid + 1,r);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}
//把自己的lazytage归零,并且给自己的儿子加上
void pushdown(int i){
    if(tree[i].lz){
        tree[i * 2].lz += tree[i].lz;//左右儿子分别加上父亲的lz
        tree[i * 2 + 1].lz += tree[i].lz;
        int mid = (tree[i].l + tree[i].r)/ 2;
        //左右分别加起来
        tree[i * 2].sum  += tree[i].lz *(mid - tree[i * 2].l + 1);
        tree[i * 2 + 1].sum += tree[i].lz * (tree[i * 2 + 1].r - mid);
        tree[i].lz = 0;//父亲lz归0
    }
    return;
}
//区间修改(数据更新)
void add(int i ,int l,int r,int k){
    //如果这个区间完全包括在目标区间内
    if(tree[i].l >= l && tree[i].r <= r){
        tree[i].sum += k*(tree[i].r - tree[i].l + 1);
        tree[i].lz += k;//记录lazytage
        return;
    }
    pushdown(i);//向下传递
    if(tree[i * 2].r >= l) add(i * 2,l,r,k);
    if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
    return;
}
int search(int i,int l,int r){
    if(tree[i].l >= l && tree[i].r <= r)
        return tree[i].sum;
    if(tree[i].r < l || tree[i].l > r)
        return 0;
    pushdown(i);
    int s = 0;
    if(tree[i * 2].r >= l) s += search(i * 2,l,r);
    if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r);
    return s;
}
signed main(){
    //freopen("in","r",stdin);
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    build(1,1,n);
    while(m--){
        int op,x,y,k;
        cin >> op;
        if(op == 1) {
            cin >> x >> y >> k;
            add(1,x,y,k);
        }
        else {
            cin >> x >> y;
            cout << search(1,x,y) << endl;
        }
    }
    return 0;
}
View Code

乘法/sqrt线段树

P3373 【模板】线段树 2

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 10;
struct node{
    int l,r;
    int sum;
    int plz,mlz;//lazytage分为两种,加法plz 乘法 mlz
}tree[maxn * 4];
int n,m,p,a[maxn];
void build(int i,int l,int r){
    tree[i].mlz = 1;
    tree[i].l = l; tree[i].r = r;
    if(l==r){
        tree[i].sum = a[l] % p;
        return;
    }
    int mid = (l + r)/ 2;
    build(i * 2,l,mid);
    build(i * 2 + 1,mid + 1,r);
    tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p;
    return;
}

void pushdown(int i){
    int k1=tree[i].mlz,k2=tree[i].plz;
    tree[i * 2].sum=(tree[i * 2].sum*k1 + k2* (tree[i * 2].r - tree[i * 2].l+1))%p;
    tree[i * 2 + 1].sum=(tree[i * 2 + 1].sum * k1+k2*(tree[i * 2 + 1].r-tree[i * 2 + 1].l + 1))%p;
    tree[i * 2].mlz=(tree[i * 2].mlz*k1)%p;
    tree[i * 2 + 1].mlz=(tree[i * 2 + 1].mlz*k1)%p;
    tree[i * 2].plz=( tree[i * 2].plz *k1 + k2)%p;
    tree[i * 2 + 1].plz=(tree[i * 2 + 1].plz * k1 + k2)%p;
    tree[i].plz=0;
    tree[i].mlz=1;
    return ;
}

void mul(int i ,int l,int r,int k){
    if(tree[i].r < l || tree[i].l > r)
        return ;
    //如果这个区间完全包括在目标区间内
    if(tree[i].l >= l && tree[i].r <= r){
        tree[i].sum = ( k * tree[i].sum) % p;
        tree[i].mlz = (tree[i].mlz * k) % p;
        tree[i].plz = (tree[i].plz * k) % p;
        return;
    }
    pushdown(i);//向下传递
    if(tree[i * 2].r >= l) mul(i * 2,l,r,k);
    if(tree[i * 2 + 1].l <= r) mul(i * 2 + 1,l,r,k);
    tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p;
    return;
}

void add(int i ,int l,int r,int k){
    if(tree[i].r < l || tree[i].l > r)
        return ;
    //如果这个区间完全包括在目标区间内
    if(tree[i].l >= l && tree[i].r <= r){
        tree[i].sum += (k *(tree[i].r - tree[i].l + 1)) % p;
        tree[i].plz = (tree[i].plz + k) % p;
        return;
    }
    pushdown(i);//向下传递
    if(tree[i * 2].r >= l) add(i * 2,l,r,k);
    if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k);
    tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p;
    return;
}
int search(int i,int l,int r){
    if(tree[i].r < l || tree[i].l > r)
        return 0;
    if(tree[i].l >= l && tree[i].r <= r)
        return tree[i].sum;
    pushdown(i);
    int s = 0;
    if(tree[i * 2].r >= l) s += search(i * 2,l,r) % p;
    if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r) % p;
    return s % p;
}
signed main(){
   // freopen("in","r",stdin);
    ios::sync_with_stdio(0);
    cin >> n >> m >> p;
    for(int i = 1; i <= n; i++) cin >> a[i];
    build(1,1,n);
    while(m--){
        int op,x,y,k;
        cin >> op;
        if(op == 1) {
            cin >> x >> y >> k;
            k %= p;
            mul(1,x,y,k);
        }
        else if(op == 2){
            cin >> x >> y >> k;
            k %= p;
            add(1,x,y,k);
        }else{
            cin >> x >> y;
            cout << search(1,x,y) << endl;
        }
    }
    return 0;
}
View Code

大佬的博客

原文地址:https://www.cnblogs.com/xcfxcf/p/12301570.html