##[$HDU$ $1698$ $Just$ $a$ $Hook$](http://acm.hdu.edu.cn/showproblem.php?pid=1698) ### 一、经验总结 * $HDU$ 是杭州电子科技大学的简称,$POJ$是北京大学$OJ$简称 * 因读入量较大,使用`cin`读入直接`TLE`,换用`scanf`后`AC`,看来能用`scanf`最好以后用`scanf`! * $HDU$和$POJ$不支持万能头文件,需要小心替换库文件 ### 二、题目理解 给你一个长 $n$ 的序列,初始值全为 $1$ ,$q$ 次操作,每次将 $[ x, y ]$ 的值改为 $z$ ,问最后整个序列的和为多少? ### 三、实现代码 ```cpp {.line-numbers} #include #include #include #include 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; } ```