HDU 1698 Just a Hook [线段树+区间修改为一个值+区间查询]
\(HDU\) \(1698\) \(Just\) \(a\) \(Hook\)
一、经验总结
- \(HDU\) 是杭州电子科技大学的简称,\(POJ\)是北京大学\(OJ\)简称
- 因读入量较大,使用
cin
读入直接TLE
,换用scanf
后AC
,看来能用scanf
最好以后用scanf
! - \(HDU\)和\(POJ\)不支持万能头文件,需要小心替换库文件
二、题目理解
给你一个长 \(n\) 的序列,初始值全为 \(1\) ,\(q\) 次操作,每次将 \([ x, y ]\) 的值改为 \(z\) ,问最后整个序列的和为多少?
三、实现代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, q;
struct Node {
int l, r;
LL sum;
int tag;
} tr[N << 2];
void pushup(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void bulid(int u, int l, int r) {
tr[u] = {l, r};
if (l == r) {
tr[u].sum = 1;
return;
}
int mid = (l + r) >> 1;
bulid(u << 1, l, mid), bulid(u << 1 | 1, mid + 1, r);
pushup(u);
}
void pushdown(int u) {
Node &root = tr[u], &ls = tr[u << 1], &rs = tr[u << 1 | 1];
if (root.tag) { // 如果懒标记不为零,需要向儿子们传递懒标记
ls.tag = root.tag, ls.sum = (LL)(ls.r - ls.l + 1) * root.tag;
rs.tag = root.tag, rs.sum = (LL)(rs.r - rs.l + 1) * root.tag;
root.tag = 0; // 清空懒标记
}
}
void modify(int u, int l, int r, int v) {
if (l <= tr[u].l && tr[u].r <= r) {
tr[u].sum = (LL)v * (tr[u].r - tr[u].l + 1);
tr[u].tag = v;
return;
}
pushdown(u); // 没有完全覆盖则分裂
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid) modify(u << 1, l, r, v);
if (r > mid) modify(u << 1 | 1, l, r, v);
pushup(u);
}
LL query(int u, int l, int r) {
if (l > tr[u].r || r < tr[u].l) return 0; // 递归出口,不在我管辖范围内的情况,返回0
if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum; // 完整区间覆盖,返回区间和
// 没有完全命中,开始分裂
pushdown(u);
// 左边+右边
return query(u << 1, l, r) + query(u << 1 | 1, l, r);
}
int main() {
// 加快读入
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
int cas = 1;
while (T--) {
cin >> n; // 线段的区间[1~n]
memset(tr, 0, sizeof tr); // 因树状数组多次使用,每次需要清空
bulid(1, 1, n); // 构建树状数组
cin >> q;
while (q--) {
int l, r, d;
cin >> l >> r >> d;
modify(1, l, r, d);
}
printf("Case %d: The total value of the hook is %lld.\n", cas++, query(1, 1, n));
}
return 0;
}