初识 线段树

Posted 落月摇情满江树

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识 线段树相关的知识,希望对你有一定的参考价值。

              线段树

作为一个刚接触线段树不就的OI新手,我认为线段树一般是区间或单点的查询或修改

如果不用线段树写应该比较难想吧(I think)

下面粘一些本蒟蒻的板子代码:

洛谷:

技术分享图片
#include<algorithm>
#include<cstdio>
#define N 200001
using namespace std;
int n, m, a, t;
struct nond {
    int ll, rr;
    long long sum, flag;
}tree[4*N];
void tree_up(int now) {
    tree[now].sum = tree[now*2].sum+tree[now*2+1].sum;
}
void tree_down(int now) {
    tree[now*2].flag += tree[now].flag;
    tree[now*2+1].flag += tree[now].flag;
    tree[now*2].sum += (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag;
    tree[now*2+1].sum += (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag;
    tree[now].flag = 0;
    return ;
}
void tree_build(int now, int l, int r) {
    tree[now].ll = l; tree[now].rr = r;
    if(l == r) {
        scanf("%d", &tree[now].sum);
        return ;
    }
    int mid = (l+r) / 2;
    tree_build(now*2, l, mid);
    tree_build(now*2+1, mid+1, r);
    tree_up(now);
}
void tree_change(int now, int l, int r) {
    if(tree[now].ll==l && tree[now].rr==r) {
        tree[now].sum += (tree[now].rr-tree[now].ll+1) * t;
        tree[now].flag += t;
        return ;
    }
    if(tree[now].flag) tree_down(now);
    int mid = (tree[now].ll+tree[now].rr) / 2;
    if(l<=mid && mid<r) tree_change(now*2, l, mid), tree_change(now*2+1, mid+1, r);
    else if(r<=mid) tree_change(now*2, l, r);
            else tree_change(now*2+1, l, r);
    tree_up(now);
}
long long tree_query(int now, int l, int r) {
    if(tree[now].ll==l && tree[now].rr==r)
        return tree[now].sum; 
    if(tree[now].flag) tree_down(now);
    int mid = (tree[now].ll+tree[now].rr) / 2;
    if(l<=mid && mid<r) return tree_query(now*2, l, mid)+tree_query(now*2+1, mid+1, r);
    else if(r<=mid) return tree_query(now*2, l, r);
            else return tree_query(now*2+1, l, r);
}
int main() {
    scanf("%d%d", &n, &m);
    tree_build(1, 1, n);
    for(int i = 1; i <= m; i++) {
        scanf("%d", &a);
        if(a == 1) {
            int b, c;
            scanf("%d%d%d", &b, &c, &t);
            tree_change(1, b, c);
        }
        else {
            int b, c;
            scanf("%d%d", &b, &c);
            printf("%lld\n", tree_query(1, b, c));
        }
    }
    return 0;
}
P3372【模板】线段树1
技术分享图片
#include<cstdio>
#define LL long long
#define N 100001
using namespace std;
int n, m, p, x, y, z, k;
int ll[4*N], rr[4*N];
LL flag1[4*N], flag2[4*N], sum[4*N];
void up(int now) {
    sum[now] = (sum[now*2] + sum[now*2+1]) % p;
}
void down(int now) {
    if(flag1[now]!=1) {
        flag1[now*2] = flag1[now*2] * flag1[now] % p;
        flag2[now*2] = flag2[now*2] * flag1[now] % p;
        flag1[now*2+1] = flag1[now*2+1] * flag1[now] % p;
        flag2[now*2+1] = flag2[now*2+1] * flag1[now] % p;
        sum[now*2] = sum[now*2] * flag1[now] % p;
        sum[now*2+1] = sum[now*2+1] * flag1[now] % p;
        flag1[now] = 1;
    }
    if(flag2[now]) {
        flag2[now*2] = (flag2[now*2] + flag2[now]) % p;
        flag2[now*2+1] = (flag2[now*2+1] + flag2[now]) % p;
        sum[now*2] = (sum[now*2] + (rr[now*2]-ll[now*2]+1)*flag2[now]%p) % p;
        sum[now*2+1] = (sum[now*2+1] + (rr[now*2+1]-ll[now*2+1]+1)*flag2[now]%p) % p;
        flag2[now] = 0;
    }
    return ;
}
void build(int now, int l, int r) {
    ll[now] = l; rr[now] = r;
    flag1[now] = 1;
    if(l == r) {
        scanf("%lld", &sum[now]);
        return ;
    }
    int mid = (l+r) / 2;
    build(now*2, l, mid);
    build(now*2+1, mid+1, r);
    up(now);
}
void change1(int now, int l, int r) {
    if(ll[now]==l && rr[now]==r) {
        flag1[now] = flag1[now] * z %p;
        flag2[now] = flag2[now] * z % p; 
        sum[now] = sum[now] * z % p;
        return ;
    }
    if(flag2[now] || flag1[now]!=1) down(now);
    int mid = (ll[now]+rr[now]) / 2;
    if(l<=mid && mid<r) change1(now*2, l, mid), change1(now*2+1, mid+1, r);
    else if(r <= mid) change1(now*2, l, r);
            else change1(now*2+1, l, r);
    up(now);
}
void change2(int now, int l, int r) {
    if(ll[now]==l && rr[now]==r) {
        flag2[now] = (flag2[now] + z) % p;
        sum[now] = (sum[now] + (rr[now]-ll[now]+1)*z%p) % p;
        return ;
    }
    if(flag2[now] || flag1[now]!=1) down(now);
    int mid = (ll[now]+rr[now]) / 2;
    if(l<=mid && mid<r) change2(now*2, l, mid), change2(now*2+1, mid+1, r);
    else if(r <= mid) change2(now*2, l, r);
            else change2(now*2+1, l, r);
    up(now);
}
LL query(int now, int l, int r) {
    if(ll[now]==l && rr[now]==r)
        return sum[now];
    if(flag2[now] || flag1[now]!=1) down(now);
    int mid = (ll[now]+rr[now]) / 2;
    if(l<=mid && mid<r) return(query(now*2, l, mid) % p + query(now*2+1, mid+1, r) % p) % p;
    else if(r <= mid) return query(now*2, l, r) % p;
            else return query(now*2+1, l, r) % p;
}
int main() {
    scanf("%d%d%d", &n, &m, &p);
    build(1, 1, n);
    for(int i = 1; i <= m; i++) {
        scanf("%d", &k);
        if(k == 1) {scanf("%d%d%d", &x, &y, &z); change1(1, x, y); }
        if(k == 2) {scanf("%d%d%d", &x, &y, &z); change2(1, x, y); }
        if(k == 3) {scanf("%d%d", &x, &y); printf("%lld\n", query(1, x, y) % p); }
    }
    return 0;
}
P3373【模板】线段树2

codevs:

技术分享图片
#include<algorithm>
#include<cstring>
#include<cstdio>
#define N 100001
using namespace std;
int n, m;
int a, b, c;
struct note {
    int ll, rr;
    int sum;
}e[4*N];
void up(int now) {
    e[now].sum = e[now*2].sum + e[now*2+1].sum;
}
void build(int now, int l, int r) {
    e[now].ll = l;
    e[now].rr = r;
    if(l == r) {
        scanf("%d", &e[now].sum);
        return ;
    }
    int mid = (l+r) / 2;
    build(now*2, l, mid);
    build(now*2+1, mid+1, r);
    up(now);
}
void change(int now, int x, int y) {
    if(e[now].ll == e[now].rr) {
        e[now].sum += y;
        return ;
    }
    int mid = (e[now].ll+e[now].rr) / 2;
    if(x <= mid) change(now*2, x, y);
    else change(now*2+1, x, y);
    up(now);
}
int query(int now, int l, int r) {
    if(e[now].ll==l && e[now].rr==r) {
        return e[now].sum;
    }
    int mid = (e[now].ll+e[now].rr) / 2;
    if(l<=mid && mid<r) {
        return query(now*2, l, mid) + query(now*2+1, mid+1, r);
    }
    else if(r <= mid) return query(now*2, l, r);
            else return query(now*2+1, l, r);
}
int main() {
    scanf("%d", &n);
    build(1, 1, n);
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d", &a, &b, &c);
        if(a == 1) change(1, b, c);
        else printf("%d\n", query(1, b, c));
    }
    return 0;
}
1080 线段树练习
技术分享图片
#include<algorithm>
#include<cstring>
#include<cstdio>
#define N 100001
using namespace std;
int n, m, flag, t;
struct note {
    int ll, rr;
    int sum, ok;
}tree[4*N];
void tree_up(int now) {
    tree[now].sum = tree[now*2].sum + tree[now*2+1].sum;
}
void tree_down(int now) {
    tree[now*2].ok += tree[now].ok;
    tree[now*2+1].ok += tree[now].ok;
    tree[now*2].sum += (tree[now*2].rr-tree[now*2].ll+1) * tree[now].ok;
    tree[now*2+1].sum += (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].ok;
    tree[now].ok = 0;
    return ;
}
void tree_build(int now, int l, int r) {
    tree[now].ll = l; tree[now].rr = r;
    if(l == r) {
        scanf("%d", &tree[now].sum);
        return ;
    }
    int mid = (l+r) / 2;
    tree_build(now*2, l, mid);
    tree_build(now*2+1, mid+1, r);
    tree_up(now);
}
void tree_change(int now, int l, int r) {
    if(tree[now].ll==l && tree[now].rr==r) {
        tree[now].sum+=(tree[now].rr-tree[now].ll+1) * t;
        tree[now].ok += t;
        return ;
    }
    if(tree[now].ok) tree_down(now);
    int mid = (tree[now].ll+tree[now].rr) / 2;
    if(l<=mid && mid<r) tree_change(now*2, l, mid), tree_change(now*2+1, mid+1, r);
    else if(r <= mid) tree_change(now*2, l, r);
            else tree_change(now*2+1, l, r);
    tree_up(now);
}
int tree_query(int now, int l, int r) {
    if(tree[now].ll == tree[now].rr) {
        return tree[now].sum;
    }
    if(tree[now].ok) tree_down(now);
    int mid = (l+r) / 2;
    if(t <= mid) return tree_query(now*2, l, mid);
    else return tree_query(now*2+1, mid+1, r);
}
int main() {
    scanf("%d", &n);
    tree_build(1, 1, n);
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%d", &flag);
        if(flag == 1) {
            int a, b;
            scanf("%d%d%d", &a, &b, &t);
            tree_change(1, a, b);
        }
        else {
            scanf("%d", &t);
            printf("%d\n", tree_query(1, 1, n));
        }
    }
    return 0;
}
1081 线段树练习2
技术分享图片
#include<algorithm>
#include<cstdio>
#define N 200001
using namespace std;
int n, m, a, t;
struct nond {
    int ll, rr;
    long long sum, flag;
}tree[4*N];
void tree_up(int now) {
    tree[now].sum = tree[now*2].sum+tree[now*2+1].sum;
}
void tree_down(int now) {
    tree[now*2].flag += tree[now].flag;
    tree[now*2+1].flag += tree[now].flag;
    tree[now*2].sum += (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag;
    tree[now*2+1].sum += (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag;
    tree[now].flag = 0;
    return ;
}
void tree_build(int now, int l, int r) {
    tree[now].ll = l; tree[now].rr = r;
    if(l == r) {
        scanf("%d", &tree[now].sum);
        return ;
    }
    int mid = (l+r) / 2;
    tree_build(now*2, l, mid);
    tree_build(now*2+1, mid+1, r);
    tree_up(now);
}
void tree_change(int now, int l, int r) {
    if(tree[now].ll==l && tree[now].rr==r) {
        tree[now].sum += (tree[now].rr-tree[now].ll+1) * t;
        tree[now].flag += t;
        return ;
    }
    if(tree[now].flag) tree_down(now);
    int mid = (tree[now].ll+tree[now].rr) / 2;
    if(l<=mid && mid<r) tree_change(now*2, l, mid), tree_change(now*2+1, mid+1, r);
    else if(r<=mid) tree_change(now*2, l, r);
            else tree_change(now*2+1, l, r);
    tree_up(now);
}
long long tree_query(int now, int l, int r) {
    if(tree[now].ll==l && tree[now].rr==r)
        return tree[now].sum; 
    if(tree[now].flag) tree_down(now);
    int mid = (tree[now].ll+tree[now].rr) / 2;
    if(l<=mid && mid<r) return tree_query(now*2, l, mid)+tree_query(now*2+1, mid+1, r);
    else if(r<=mid) return tree_query(now*2, l, r);
            else return tree_query(now*2+1, l, r);
}
int main() {
    scanf("%d", &n);
    tree_build(1, 1, n);
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%d", &a);
        if(a == 1) {
            int b, c;
            scanf("%d%d%d", &b, &c, &t);
            tree_change(1, b, c);
        }
        else {
            int b, c;
            scanf("%d%d", &b, &c);
            printf("%lld\n", tree_query(1, b, c));
        }
    }
    return 0;
} 
1082 线段树练习3

 

以上是关于初识 线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树详解

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

线段树-代码实现细节与技巧

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)