1. 程式人生 > >HDU 1698 Just a Hook(線段樹區間更新)

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; }