HDU 1698 Just a Hook(线段树区间更新)

题意:

屠夫是Dota中一个令所有英雄闻风丧胆的英雄。他有一个很长的钩子,这个钩子是用铜做的(刚刚开始都是1),现在他想要更改这些钩子,把某个区间的钩子改为金、银或铜。
输入 L, R, X 表示把 L~R的区间的数字改为 X。最后求[1, N]的和。

解析:

这题是线段树区间修改的模板题。
更新的时候采用了一种叫做延迟更新的技术,即需要更新某个区间的时候,暂时只更新这个区间,其子区间在有需要的时候再更新(否则每次更新都要遍历到子区间,时间复杂度会大大的上升),于是又加了一个setv的延迟标志(有值表示没有向下更新的,没有值表示已经“最新”)

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls o*2
#define rs o*2+1
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
int ql, qr, val;
int sumv[N<<2], setv[N<<2];

void maintain(int o) {
    sumv[o] = sumv[ls] + sumv[rs];
}

void build(int o, int L, int R) {
    setv[o] = 0;
    sumv[o] = 1;
    if(L == R)
        return;
    int M = (L+R)/2;
    build(ls, L, M);
    build(rs, M+1, R);
}

void pushdown(int o, int M) {
    if(setv[o]) {
        setv[ls] = setv[rs] = setv[o];
        sumv[ls] = (M-(M>>1)) * setv[o]; 
        sumv[rs] = (M>>1) * setv[o];
        setv[o] = 0;
    }
}

void modify(int o, int L, int R) {
    if(ql <= L && R <= qr) {
        setv[o] = val;
        sumv[o] = val * (R-L+1);
        return;
    }
    pushdown(o, R-L+1);
    int M = (L+R)/2;
    if(ql <= M) modify(ls, L, M);
    if(qr > M) modify(rs, M+1, R);
    maintain(o);
}

int _sum;
void query(int o, int L, int R) {
    if(setv[o]) {
        _sum += setv[o] * (min(R, qr) - max(L,ql) + 1);
    }else if(ql <= L && R <= qr) {
        _sum += sumv[o];
    }else {
        int M = (L+R)/2;
        if(ql <= M) query(ls, L, M);
        if(qr > M) query(rs, M+1, R);
    }
}

int main() {
    int n, q;
    int T, cas = 1;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &q);
        build(1, 1, n);
        while(q--) {
            scanf("%d%d%d", &ql, &qr, &val);
            modify(1, 1, n);
        }
        ql = 1, qr = n, _sum = 0;
        query(1, 1, n);
        printf("Case %d: The total value of the hook is %d.\n", cas++, _sum);
    }
    return 0;
}

你可能感兴趣的:(HDU,1698)