码迷,mamicode.com
首页 > 其他好文 > 详细

线段树

时间:2019-06-11 12:56:19      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:计算   序列   范围   inf   ret   最小值   执行   区间   最大   

点修改
Update(x,v): 吧Ax修改为v
Query(L,R): 计算{AL,AL+1,...,AR}
minv[o]表示节点o所对应的区间中所有元素的最小值

int ql, qr; //查询[ql, qr]中的最小值
int query(int o, int L, int R){
    int M = L + (R-L)/2, ans = INF;
    if(ql <= L && qr >= R) return minv[o];
    if(ql <= M) ans = min(ans, query(2*o, L, M));
    if(qr > M) ans = min(ans, query(2*o+1, M+1, R));
    return ans;
}

int p, v; //修改: A[p] = v;
void update(int o, int L, int R){
    int M = L + (R - L)/2;
    if(L == R) minv[o] = v;
    else{
        if(p <= M) update(2*o, L, M);else update(2*o+1, M+1, R);
        minv[o] = min(minv[2*o], min[2*o+1]);
    }
}

区间修改
Add(L, R, v): 把AL, AL+1, ..., AR的值全部增加v
Query(L, R): 计算子序列AL,AL+1, ...,AR的元素和、最小值和最大值
sum[o]表示“如果只执行节点o及其子孙节点中的add操作,结点o对应区间中所有数之和”

//修改/查询范围均为[y1, y2]

void maintain(int o, int L, int R){
    int lc = 2*o, int lr = 2*o+1;
    sumv[o] = minv[o] = maxv[o] = 0;
    if(R > L){
        sumv[o] = sumv[lc] + sumv[lr];
        minv[o] = min(minv[lc], minv[rc]);
        maxv[o] = max(maxv[lc], maxv[rc]);
    }
    minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+1);
}

void update(int o, int L, int R){
    int lc = 2*o, rc = 2*o+1;
    if(y1 <= L && y2 >= R){
        addv[o] += v;
    } else {
        int M = L + (R - L)/2;
        if(y1 <= M) update(lc, L, M);
        if(y2 > M) update(rc, M+1, R);
    }
    maintain(o, L, R);
}

//查询
int _min, _max, _sum;
void query(int o, int L, int R, int add) {
    if(y1 <= L && y2 >= R){
        _sum += sumv[o] + add * (R-L+1);
        _min = min(_min, minv[o] + add);
        _max = max(_max, maxv[o] + add);
    } else {
        int M = L + (R - L)/2;
        if(y1 <= M) query(2*o, L, M, add + addv[o]);
        if(y2 > M) query(2*o+1, M+1, R, add + addv[o]);
    }
}

快速序列操作
Set(L, R, v): 把AL, AL+1, ..., AR的值全部修改为v (v>=0)
Query(L, R): 计算子序列AL, AL+1, ..., AR的元素和、最小值和最大值

void pushdown(int o){
    int lc = 2*o, rc = 2*o+1;
    if(setv[o] >= 0) {
        set[lc] = set[rc] = setv[o];
        setv[o] = -1;
    }
}

void update(int o, int L, int R) {
    int lc = 2*o, rc = 2*o+1;
    if(y1 <= L && y2 >= R) {
        setv[o] = v;
    } else {
        pushdown(o);
        int M = L + (R - L)/2;
        if(y1 <= M) update(lc, L, M); else maintain(lc, L, M);
        if(y2 > M) update(rc, M+1, R); else maintain(rc, M+1, R);
    }
    maintain(o, L, R);
}

void query(int o, int L, int R){
    if(setv[o] >= 0) {
        _sum += setv[o] * (min(R, y2) - max(L, y1) + 1);
        _min = min(_min, setv[o]);
        _max = max(_max, setv[o]);
    } else if(y1 <= L && y2 >= R) {
        _sum += sumv[o];
        _min = min(_min, minv[o]);
        _max = max(_max, maxv[o]);
    } else {
        int M = L + (R - L)/2;
        if(y1 <= M) query(2*o, L, M);
        if(y2 > M) query(2*o+1, M+1, R);
    }
}

 

线段树

标签:计算   序列   范围   inf   ret   最小值   执行   区间   最大   

原文地址:https://www.cnblogs.com/hanasaki/p/11002554.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!