kuangbin 线段树题单 代码

73 篇文章 0 订阅
这篇博客介绍了四种常见的区间操作问题的解决方案,包括单点修改、区间和查询、区间最大值查询以及区间修改、区间和查询。通过模板代码展示了如何使用线段树和珂朵莉树(Old Driver Tree)解决这些问题,适用于ACM/ICPC竞赛和算法学习。
摘要由CSDN通过智能技术生成

题单链接
https://vjudge.net/article/752

别人的笔记 https://blog.csdn.net/weixin_45799835/article/details/110069469

精选:4

1. HDU-1166 敌兵布阵

单点修改,区间和查询模板

#include <cstdio>
#include <iostream>
#include <string>
using namespace std;


template<int maxn>
struct segment_tree {
#define LX(x) ((x)<<1)
#define RX(x) (((x)<<1)|1)
    struct node {
        int val;
        int l, r;
    } a[maxn*5+10];

    void merge(int x) {
        a[x].val = a[LX(x)].val + a[RX(x)].val;
    }

    void build(int x, int l, int r) {
        a[x].l = l;
        a[x].r = r;
        if (l==r) {
            scanf("%d", &a[x].val);
            return;
        }
        build(LX(x), l, (l+r)>>1);
        build(RX(x), ((l+r)>>1)+1, r);
        merge(x);
    }

    void modify_add(int x, int pos, int val) {
        if (a[x].l == a[x].r) {
            a[x].val += val;
            return;
        }
        int lx=LX(x), rx=RX(x);
        if (pos <= a[lx].r)
            modify_add(lx, pos, val);
        if (pos >= a[rx].l)
            modify_add(rx, pos, val);
        merge(x);
    }

    int query(int x, int L, int R) {
        if (a[x].l>=L && a[x].r<=R) {
            return a[x].val;
        }
        int ret=0;
        int lx=LX(x), rx=RX(x);
        if (L <= a[lx].r)
            ret += query(lx, L, R);
        if (R >= a[rx].l)
            ret += query(rx, L, R);
        return ret;
    }
#undef LX
#undef RX
};


int n;
segment_tree<50000> T;

void solve()
{
    cin >>n;
    T.build(1, 1, n);
    string op;
    int i, j;
    while (1) {
        cin >>op;
        if (op=="Add") {
            cin >>i >>j;
            T.modify_add(1, i, j);
        }
        else if (op=="Sub") {
            cin >>i >>j;
            T.modify_add(1, i, -j);
        }
        else if (op=="Query") {
            cin >>i >>j;
            cout <<T.query(1, i, j) <<'\n';
        }
        else if (op=="End") {
            break;
        }
    }

}


int main()
{
    int ttt;
    cin >>ttt;
    for (int i=1; i<=ttt; i++) {
        cout <<"Case " <<i <<":\n";
        solve();
    }
    return 0;
}

/*

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End 


*/

2. HDU-1754 I Hate It

单点修改,区间最大值查询模板

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;


template<int maxn>
struct segment_tree {
#define LX(x) ((x)<<1)
#define RX(x) (((x)<<1)|1)
    struct node {
        int val_max;
        int l, r;
    } a[maxn*4+10];

    void merge(int x) {
        a[x].val_max = max(a[LX(x)].val_max, a[RX(x)].val_max);
    }

    void build(int x, int l, int r) {
        a[x].l = l;
        a[x].r = r;
        if (l==r) {
            scanf("%d", &a[x].val_max);
            return;
        }
        build(LX(x), l, (l+r)>>1);
        build(RX(x), ((l+r)>>1)+1, r);
        merge(x);
    }

    void modify(int x, int pos, int val) {
        if (a[x].l==a[x].r) {
            a[x].val_max = val;
            return;
        }
        int lx=LX(x), rx=RX(x);
        if (pos <= a[lx].r)
            modify(lx, pos, val);
        if (pos >= a[rx].l)
            modify(rx, pos, val);
        merge(x);
    }

    int query(int x, int L, int R) {
        if (L<=a[x].l && a[x].r<=R) {
            return a[x].val_max;
        }
        int lx=LX(x), rx=RX(x);
        int ret=0;
        if (L<=a[lx].r)
            ret = max(ret, query(lx, L, R));
        if (R>=a[rx].l)
            ret = max(ret, query(rx, L, R));
        return ret;
    }

#undef LX
#undef RX
};

int n, m;
segment_tree<200005> T;

bool solve()
{
    if (scanf("%d%d", &n, &m) != 2)
        return false;
    
    T.build(1, 1, n);
    while (m--) {
        char op[5];
        int i, j;
        scanf("%s%d%d", op, &i, &j);
        if (*op=='Q') {
            printf("%d\n", T.query(1, i, j));
        }
        else {
            T.modify(1, i, j);
        }
    }


    return true;
}



int main()
{
    while (solve())
        ;
    return 0;
}

3. POJ-3468 A Simple Problem with Integers

区间修改,区间和查询模板

// https://vjudge.net/problem/POJ-3468
#include <cstdio>
#include <iostream>
using namespace std;


template<typename t_val, int maxn>
struct segment_tree {
#define LX(x) ((x)<<1)
#define RX(x) (((x)<<1)|1)
#define SZ(x) (a[x].r-a[x].l+1)
    struct node {
        t_val val;
        t_val tag;
        int l, r;
    } a[maxn*4+10];

    void merge(int x) {
        a[x].val = a[x].tag*SZ(x);
        a[x].val += a[LX(x)].val;
        a[x].val += a[RX(x)].val;
    }

    void down_tag(int x) {
        int lx=LX(x), rx=RX(x);
        a[lx].tag += a[x].tag;
        a[lx].val += a[x].tag * SZ(lx);
        a[rx].tag += a[x].tag;
        a[rx].val += a[x].tag * SZ(rx);
        a[x].tag = 0;
    }

    void build(int x, int l, int r) {
        a[x].l = l;
        a[x].r = r;
        a[x].tag = 0;
        if (l==r) {
            scanf("%lld", &a[x].val);
            return;
        }
        build(LX(x), l, (l+r)>>1);
        build(RX(x), ((l+r)>>1)+1, r);
        merge(x);
    }

    void modify_add(int x, int L, int R, t_val val) {
        if (L<=a[x].l && a[x].r<=R) {
            a[x].val += val*SZ(x);
            a[x].tag += val;
            return;
        }
        const int lx = LX(x), rx=RX(x);
        down_tag(x);
        if (L<=a[lx].r)
            modify_add(lx, L, R, val);
        if (R>=a[rx].l)
            modify_add(rx, L, R, val);
        merge(x);
    }

    t_val query(int x, int L, int R) {
        if (L<=a[x].l && a[x].r<=R) {
            return a[x].val;
        }
        down_tag(x);
        t_val ret=0;
        int lx=LX(x), rx=RX(x);
        if (L<=a[lx].r)
            ret += query(lx, L, R);
        if (R>=a[rx].l)
            ret += query(rx, L, R);
        return ret;
    }

#undef LX
#undef RX
};

int n, q;
segment_tree<long long, 100005> T;

void solve()
{
    cin >>n >>q;

    T.build(1, 1, n);

    char op[5];
    int a, b, c;
    while (q--) {
        scanf("%s", op);
        if (*op=='C') {
            scanf("%d%d%d", &a, &b, &c);
            T.modify_add(1, a, b, c);
        }
        else {
            scanf("%d%d", &a, &b);
            printf("%lld\n", T.query(1, a, b));
        }
    }

}


int main()
{
    solve();
    return 0;
}

4. POJ-2528 Mayor’s posters

5. HDU-1698 Just a Hook

和 4 一样是线段覆盖,尝试了一下用珂朵莉树。
珂朵莉树资料 https://oi-wiki.org/ds/odt/

#include <cstdio>
#include <set>
using namespace std;

struct Old_Driver_Tree {

    struct node_t {
        int l, r;
        mutable int v;

        node_t(const int &l_, const int &r_, const int &v_): l(l_), r(r_), v(v_) {}

        bool operator<(const node_t &o) const {return l<o.l;}
    };

    set<node_t> odt;
    int maxn;

    void init(int n) {
        maxn = n;
        odt.clear();
        odt.insert(node_t(1, maxn, 1));  // 一开始全是1
    }

    // 返回指向以 x 为左端点的区间的迭代器
    set<node_t>::iterator split(int x) {
        if (x>maxn) return odt.end();
        auto it = --odt.upper_bound(node_t(x, 0, 0));
        if (it->l == x) return it;
        int l = it->l, r = it->r, v = it->v;
        odt.erase(it);
        odt.insert(node_t(l, x-1, v));
        return odt.insert(node_t(x, r, v)).first;
    }

    // 将 [l, r] 区间赋值为 v,会将 set 中该区间包含的所有节点合并为一个节点
    // 注意先求 itr,再求 itl。否则 itr 可能会失效
    void assign(int l, int r, int v) {
        auto itr = split(r+1);
        auto itl = split(l);
        odt.erase(itl, itr);
        odt.insert(node_t(l, r, v));
    }
};

Old_Driver_Tree TT;

void solve(int iidd)
{
    int n , q, xx, yy, zz;
    int ans=0;
    scanf("%d%d", &n, &q);
    TT.init(n);
    while (q--) {
        scanf("%d%d%d", &xx, &yy, &zz);
        TT.assign(xx, yy, zz);
    }
    for (auto &i: TT.odt) {
        //printf("%d %d %d\n", i.l, i.r, i.v);
        ans += (i.r-i.l+1)*i.v;
    }
    printf("Case %d: The total value of the hook is %d.\n", iidd, ans);
}

int main()
{
    int ttt;
    scanf("%d", &ttt);
    for (int tt=1; tt<=ttt; tt++) {
        solve(tt);
    }
    return 0;
}

/*

1
10
2
1 5 2
5 9 3

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值