线段树[模板]

前言

线段树是一个非常实用的数据结构, 并且使用频率非常高. 所有操作都能在log时间内完成, 虽然常数要比树状数组大, 但是比起很多平衡树来说常数还是小了不少. 线段树的应用范围很广, 许多操作都能够支持.
关键是, 线段树好写好调, 完全不恶心.
除非操作非常简单, 尽量不要用树状数组. 线段树虽然代码要比树状数组大但还是很好写的, 关键是线段树要比树状数组应用范围广的多. 关于区间操作尽量用线段树.
最后要注意的就是, 能用线段树的千万不要作死去手写平衡树, 尤其是splay.

下面给出Codevs两道最简单的和操作最全的线段树.

Codevs 线段树练习

最简单滴~

#include<stdio.h>
const int maxn = 1e5 + 5;
typedef long long lnt;
int n, q;
int a[maxn];
struct node
{
    node *ls, *rs;
    lnt sum;
    inline void update()
    {
        sum = ls->sum + rs->sum;
    }
}pool[maxn * 4], *tail = pool, *root;
node* build(int lf, int rg)
{
    node* bt = ++tail;
    if(lf == rg)
    {
        bt->sum = a[lf];
        return bt;
    }
    int mid = (lf + rg) >> 1;
    bt->ls = build(lf, mid);
    bt->rs = build(mid + 1, rg);
    bt->update();
    return bt;
}
void modify(node* bt, int lf, int rg, int pos, int delta)
{
    if(lf == rg)
    {
        bt->sum += delta;
        return;
    }
    int mid = (lf + rg) >> 1;
    if(pos <= mid) modify(bt->ls, lf, mid, pos, delta);
    else modify(bt->rs, mid + 1, rg, pos, delta);
    bt->update();
}
lnt query(node* bt, int lf, int rg, int L, int R)
{
    if(L <= lf && rg <= R) return bt->sum;
    int mid = (lf + rg) >> 1;
    lnt rt = 0;
    if(L <= mid) rt += query(bt->ls, lf, mid, L, R);
    if(R > mid) rt += query(bt->rs, mid + 1, rg, L, R);
    return rt; 
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    root = build(1, n);
    scanf("%d", &q);
    for (int i = 1; i <= q; ++ i)
    {
        int opt, l, r;
        scanf("%d%d%d", &opt, &l, &r);
        if(opt == 1) modify(root, 1, n, l, r);
        if(opt == 2) printf("%lld\n", query(root, 1, n, l, r));
    }
}

Codevs 线段树练习5

注意逻辑关系.

#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long lnt;
const int maxn = 1e5 + 5;
const lnt inf = (lnt)1 << 62;
int n, m;
lnt a[maxn];
char ss[maxn];
struct node
{
    node *ls, *rs;
    lnt sum, fix, cmax, cmin;
    int flag;
    inline void pushdown(int lf, int rg)
    {
        if(flag == 1)// add
        {
            int mid = (lf + rg) >> 1;
            ls->sum += (mid - lf + 1) * fix; 
            rs->sum += (rg - mid) * fix;
            ls->cmax += fix, rs->cmax += fix;
            ls->cmin += fix, rs->cmin += fix; 
            if(!ls->flag) ls->flag = 1;
            if(!rs->flag) rs->flag = 1;
            ls->fix += fix, rs->fix += fix;
        }
        if(flag == 2)// val
        {
            int mid = (lf + rg) >> 1;
            ls->sum = (mid - lf + 1) * fix;
            rs->sum = (rg - mid) * fix;
            ls->cmax = ls->cmin = fix;
            rs->cmax = rs->cmin = fix;
            ls->flag = rs->flag = 2;
            ls->fix = rs->fix = fix;
        }
        flag = 0, fix = 0;
    }
    inline void update()
    {
        sum = ls->sum + rs->sum;
        cmax = max(ls->cmax, rs->cmax);
        cmin = min(ls->cmin, rs->cmin);
    }
}pool[maxn * 4], *tail = pool, *root;
node* build(int lf, int rg)
{
    node* bt = ++tail;
    if(lf == rg)
    {
        bt->cmax = bt->cmin = bt->sum = a[lf];
        bt->flag = bt->fix = 0;
        return bt;
    }
    int mid = (lf + rg) >> 1;
    bt->ls = build(lf, mid);
    bt->rs = build(mid + 1, rg);
    bt->flag = bt->fix = 0;
    bt->update();
    return bt;
}
void modify(node* bt, int lf, int rg, int L, int R, lnt delta, int opt)
{
    if(L <= lf && rg <= R)
    {
        if(opt)
        {
            bt->flag = 2, bt->fix = delta;
            bt->sum = (rg - lf + 1) * delta; 
            bt->cmax = bt->cmin = delta;
        }
        else
        {
            bt->fix += delta; 
            if(bt->flag != 2) bt->flag = 1;
            bt->sum += (rg - lf + 1) * delta;
            bt->cmax += delta, bt->cmin += delta;
        } 
        return;
    }
    bt->pushdown(lf, rg);
    int mid = (lf + rg) >> 1;
    if(L <= mid) modify(bt->ls, lf, mid, L, R, delta, opt);
    if(R > mid) modify(bt->rs, mid + 1, rg, L, R, delta, opt);
    bt->update();
}
lnt query_sum(node* bt, int lf, int rg, int L, int R)
{
    if(L <= lf && rg <= R) return bt->sum;
    bt->pushdown(lf, rg);
    int mid = (lf + rg) >> 1;
    lnt rt = 0;
    if(L <= mid) rt += query_sum(bt->ls, lf, mid, L, R);
    if(R > mid) rt += query_sum(bt->rs, mid + 1, rg, L, R);
    bt->update();
    return rt;
}
lnt query_max(node* bt, int lf, int rg, int L, int R)
{
    if(L <= lf && rg <= R) return bt->cmax;
    bt->pushdown(lf, rg);
    int mid = (lf + rg) >> 1;
    lnt rt1 = 0, rt2 = 0;
    if(L <= mid) rt1 = query_max(bt->ls, lf, mid, L, R);
    if(R > mid) rt2 = query_max(bt->rs, mid + 1, rg, L, R);
    bt->update();
    return max(rt1, rt2);
}
lnt query_min(node* bt, int lf, int rg, int L, int R)
{
    if(L <= lf && rg <= R) return bt->cmin;
    bt->pushdown(lf, rg);
    int mid = (lf + rg) >> 1;
    lnt rt1 = inf, rt2 = inf;
    if(L <= mid) rt1 = query_min(bt->ls, lf, mid, L, R);
    if(R > mid) rt2 = query_min(bt->rs, mid + 1, rg, L, R);
    bt->update();
    return min(rt1, rt2);
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++ i) scanf("%lld", &a[i]);
    root = build(1, n);
    for (int i = 1; i <= m; ++ i)
    {
        scanf("%s", ss);
        int l, r; lnt val;
        scanf("%d%d", &l, &r);
        if(ss[0] == 'a')
        {
            scanf("%lld", &val);
            modify(root, 1, n, l, r, val, 0);
        }
        if(ss[0] == 's' && ss[1] == 'e')
        {
            scanf("%lld", &val);
            modify(root, 1, n, l, r, val, 1);
        }
        if(ss[0] == 's' && ss[1] == 'u') printf("%lld\n", query_sum(root, 1, n, l, r));
        if(ss[0] == 'm' && ss[1] == 'a') printf("%lld\n", query_max(root, 1, n, l, r));
        if(ss[0] == 'm' && ss[1] == 'i') printf("%lld\n", query_min(root, 1, n, l, r));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值