学长总结的线段树 单点增减/替换 区间替换 区间增减

HDU 1166
HDU 1754
HDU 1394

HDU 1698
POJ 3468

// 单点增减/替换,区间查询

#include 
#include 
using namespace std;

// lson, rson 分别表示左孩子和右孩子,在后面的函数中传参使用
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int MAXN = 最大n;
const int INF = 0x3f3f3f3f;

int MIN[MAXN<<2], MAX[MAXN<<2], SUM[MAXN<<2];

void PushUp(int rt) { // 向上更新,rt 表示当前结点的编号
    SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
    MIN[rt] = min(MIN[rt<<1], MIN[rt<<1|1]);
    MAX[rt] = max(MAX[rt<<1], MAX[rt<<1|1]);
}

// 下面函数的参数中:
// l, r 分别表示当前递归到的结点的作用区间 [l, r]
// rt 为当前递归到的结点的编号

// 下面所有函数调用时 l, r, rt 都传入参数 (1, n, 1)
// (1, n, 1) 表示编号为 1 ,作用区间 [1, n] 的结点,即根节点
void Build(int l, int r, int rt) {
    if(l == r) {
        // 初始化线段树为 0 的写法
        SUM[rt] = MAX[rt] = MIN[rt] = 0;
        // 边读入边建树的写法,复杂度 O(n),若执行 n 次更新来初始化的话复杂度为 O(nlogn)
        // scanf("%d", &SUM[rt]);
        // MIN[rt] = MAX[rt] = SUM[rt];
        return;
    }
    int m = (l + r) >> 1;
    Build(lson);
    Build(rson);
    PushUp(rt);
}

// 单点替换,把 p 位置的值置为 v
void UpdateV(int p, int v, int l, int r, int rt) {
    if(l == r) { // 当低轨道叶结点时,更新值并返回
        SUM[rt] = v;
        MIN[rt] = v;
        MAX[rt] = v;
        return;
    }
    int m = (l + r) >> 1;
    if(p <= m) UpdateV(p, v,lson); // 如果在左边,则向左孩子递归
    else UpdateV(p, v, rson); // 否则向右孩子递归
    PushUp(rt); // 回溯时向上更新父结点
}

// 单点增减,把 p 位置的值增加 d
void UpdateD(int p, int d, int l, int r, int rt) {
    if(l == r) {
        SUM[rt] = SUM[rt] + d;
        MIN[rt] = MIN[rt] + d;
        MAX[rt] = MAX[rt] + d;
        return;
    }
    int m = (l + r) >> 1;
    if(p <= m) UpdateD(p, d, lson);
    else UpdateD(p, d, rson);
    PushUp(rt);
}

// 求 L~R 的和
int QuerySum(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return SUM[rt];
    int m = (l + r) >> 1;
    int ret = 0;
    if(L <= m) ret += QuerySum(L, R, lson); // 如果跨左半边区间,向左孩子递归
    if(R > m) ret += QuerySum(L, R, rson); // 如果跨右半边区间,向右孩子递归

    return ret;
}

// 求 L~R 的最小值
int QueryMin(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return MIN[rt];
    int m = (l + r) >> 1;
    int ret = INF;
    if(L <= m) ret = min(ret, QueryMin(L, R, lson));
    if(R > m) ret = min(ret, QueryMin(L, R, rson));

    return ret;
}

// 求 L~R 的最大值
int QueryMax(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return MAX[rt];
    int m = (l + r) >> 1;
    int ret = -INF;
    if(L <= m) ret = max(ret, QueryMax(L, R, lson));
    if(R > m) ret = max(ret, QueryMax(L, R, rson));

    return ret;
}
// 区间替换,区间查询

#include 
#include 
using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int MAXN = 最大n;
const int INF = 0x3f3f3f3f;

int SUM[MAXN<<2], MIN[MAXN<<2], MAX[MAXN<<2];
int lazy[MAXN<<2];

void PushUp(int rt) { // 由左孩子、右孩子向上更新父节点
    SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
    MIN[rt] = min(MIN[rt<<1], MIN[rt<<1|1]);
    MAX[rt] = max(MAX[rt<<1], MAX[rt<<1|1]);
}

void PushDown(int rt, int m) { // 向下更新
    if(lazy[rt]) {
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        SUM[rt<<1] = (m - (m >> 1)) * lazy[rt];
        SUM[rt<<1|1] = ((m >> 1)) * lazy[rt];
        MIN[rt<<1] = MIN[rt<<1|1] = lazy[rt];
        MAX[rt<<1] = MAX[rt<<1|1] = lazy[rt];
        lazy[rt] = 0;
    }
}

// 以下的 l, r, rt 带入 1, n, 1
void Build(int l, int r, int rt) {
    lazy[rt] = 0;
    if(l== r) {
        // 初始化树为 0 的写法
        SUM[rt] = MIN[rt] = MAX[rt] = 0; 
        // 边读入边建树的方法
        // scanf("%d", &SUM[rt]);  
        // MIN[rt] = MAX[rt] = SUM[rt];
        return;
    }
    int m = (l + r) >> 1;
    Build(lson);
    Build(rson);
    PushUp(rt);
}

// 将 L~R 区间的值置为 v
void Update(int L, int R, int v, int l, int r, int rt) {
    if(L<=l && r<=R) {
        lazy[rt] = v;
        SUM[rt] = v * (r - l + 1);
        MIN[rt] = v;
        MAX[rt] = v;
        return;
    }
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    if(L <= m) Update(L, R, v, lson);
    if(R > m) Update(L, R, v, rson);
    PushUp(rt);
}

// 求区间 L~R 的和
int QuerySum(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return SUM[rt];
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = 0;
    if(L <= m) ret += QuerySum(L, R, lson);
    if(R > m) ret += QuerySum(L, R, rson);

    return ret;
}

// 求区间 L~R 的最小值
int QueryMin(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return MIN[rt];
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = INF;
    if(L <= m) ret = min(ret, QueryMin(L, R, lson));
    if(R > m) ret = min(ret, QueryMin(L, R, rson));

    return ret;
}

// 求区间 L~R 的最大值
int QueryMax(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return MAX[rt];
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = -INF;
    if(L <= m) ret = max(ret, QueryMax(L, R, lson));
    if(R > m) ret = max(ret, QueryMax(L, R, rson));

    return ret;
}
// 区间增减,区间查询

#include 
#include 
using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int MAXN = 最大n;
const int INF = 0x3f3f3f3f;

int SUM[MAXN<<2], MIN[MAXN<<2], MAX[MAXN<<2];
int lazy[MAXN<<2];

void PushUp(int rt) {
    SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
    MIN[rt] = min(MIN[rt<<1], MIN[rt<<1|1]);
    MAX[rt] = max(MAX[rt<<1], MAX[rt<<1|1]);
}

void PushDown(int rt, int m) {
    if(lazy[rt]) {
        lazy[rt<<1] += lazy[rt];
        lazy[rt<<1|1] += lazy[rt];
        SUM[rt<<1] += lazy[rt] * (m - (m >> 1));
        SUM[rt<<1|1] += lazy[rt] * (m >> 1);
        MIN[rt<<1] += lazy[rt];
        MIN[rt<<1|1] += lazy[rt];
        MAX[rt<<1] += lazy[rt];
        MAX[rt<<1|1] += lazy[rt];
        lazy[rt] = 0;
    }
}

// 以下的 l, r, rt 带入 1, n, 1
void Build(int l, int r, int rt) {
    lazy[rt] = 0;
    if(l == r) {
        // 初始化树为 0 的写法
        SUM[rt] = MIN[rt] = MAX[rt] = 0;
        // 边读入边建树的写法
        // scanf("%d", &SUM[rt]);
        // MIN[rt] = MAX[rt] = SUM[rt];
        return;
    }
    int m = (l + r) >> 1;
    Build(lson);
    Build(rson);
    PushUp(rt);
}

// 将区间 L~R 的值增加 v
void Update(int L, int R, int v, int l, int r, int rt) {
    if(L<=l && r<=R) {
        lazy[rt] += v;
        SUM[rt] += v * (r - l + 1);
        MIN[rt] += v;
        MAX[rt] += v;
        return;
    }
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    if(L <= m) Update(L, R, v, lson);
    if(R > m) Update(L, R, v, rson);
    PushUp(rt);
}

// 求区间 L~R 的和
int QuerySum(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return SUM[rt];
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = 0;
    if(L <= m) ret += QuerySum(L, R, lson);
    if(R > m) ret += QuerySum(L, R, rson);

    return ret;
}

// 求区间 L~R 的最小值
int QueryMin(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return MIN[rt];
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = INF;
    if(L <= m) ret = min(ret, QueryMin(L, R, lson));
    if(R > m) ret = min(ret, QueryMin(L, R, rson));

    return ret;
}

// 求区间 L~R 的最大值
int QueryMax(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R) return MAX[rt];
    PushDown(rt, r-l+1);
    int m = (l + r) >> 1;
    int ret = -INF;
    if(L <= m) ret = max(ret, QueryMax(L, R, lson));
    if(R > m) ret = max(ret, QueryMax(L, R, rson));

    return ret;
}

你可能感兴趣的:(数据结构,线段树)