HDU 1698 Just a Hook(線段樹區間更新)
阿新 • • 發佈:2019-01-05
題意:
屠夫是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;
}