#HDU 1698 Just a Hook 【线段树板题】

本文介绍了一种使用线段树解决游戏DotA中Pudge肉钩价值计算问题的方法。通过区间更新和整体查询的技术,实现了对肉钩上金属棒价值的有效变更与计算。

题目:

Just a Hook

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 25872    Accepted Submission(s): 12918


Problem Description
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.



Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.
 

Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
 

Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.
 

Sample Input
   
1 10 2 1 5 2 5 9 3
 

Sample Output
   
Case 1: The total value of the hook is 24.
 

Source
 

Recommend
wangye

思路:标准线段树模板题,区间更新,整体查询。
注意求和、初始值均为1。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <algorithm>

#define MAXN 200010
long long lazy[2 * MAXN];
long long t[2 * MAXN], a[2 * MAXN];

//int be[MAXN], ed[MAXN];
//int hips[2 * MAXN];
//double endhips[4 * MAXN];
//int maxn;

using namespace std;

void BuildTree(int l, int r, int x){
	if (l == r)
	{
		t[x] = a[l];
		return;
	}
	int m = (l + r) >> 1;
	BuildTree(l, m, x << 1);
	BuildTree(m + 1, r, x << 1 | 1);
	t[x] = t[x << 1] + t[x << 1 | 1];
	return;
}

void PushDown(int l, int r, int x){
	int m = (l + r) >> 1;
	if (lazy[x]){
		t[x << 1] = lazy[x] * (m - l + 1);
		t[x << 1 | 1] = lazy[x] * (r - m);
		lazy[x << 1 | 1] = lazy[x];
		lazy[x << 1] = lazy[x];
		lazy[x] = 0;
	}
	return;
}

void Modify(int pos, int val, int l, int r, int x){
	if (pos == l && r == l)
	{
		t[x] = val;
		return;
	}
	int m = (l + r) >> 1;
	if (pos <= m)
	{
		Modify(pos, val, l, m, x << 1);
	}
	else Modify(pos, val, m + 1, r, x << 1 | 1);
	t[x] = t[x << 1] + t[x << 1 | 1];
	return;
}

void SegModify(int L, int R, int val, int l, int r, int x){
	if (l == L&&r == R){
		t[x] = (R - L + 1)*val;
		lazy[x] = val;
		return;
	}
	PushDown(l, r, x);
	int m = (l + r) >> 1;
	if (R <= m)SegModify(L, R, val, l, m, x << 1);
	else if (L>m)SegModify(L, R, val, m + 1, r, x << 1 | 1);
	else {
		SegModify(L, m, val, l, m, x << 1);
		SegModify(m + 1, R, val, m + 1, r, x << 1 | 1);
	}
	t[x] = t[x << 1] + t[x << 1 | 1];
	return;
}

long long Query(int L, int R, int l, int r, int x){
	if (L == l && R == r)
		return t[x];
	PushDown(l, r, x);
	int m = (l + r) >> 1;
	if (R <= m)return Query(L, R, l, m, x << 1);
	else if (L>m)return Query(L, R, m + 1, r, x << 1 | 1);
	else return Query(L, m, l, m, x << 1) + Query(m + 1, R, m + 1, r, x << 1 | 1);
}

int main()
{


	int nn, mm;
	int ts;
	cin >> ts;
	int is = 1;
	while (ts--)
	{
		cin >> nn >> mm;
		memset(t, 0, sizeof(t));
		memset(lazy, 0, sizeof(lazy));
		memset(a, 0, sizeof(a));

		int n = 1;
		while (n < nn)
		{
			n *= 2;
		}
		for (size_t i = 1; i <= nn; i++)
		{
			a[i] = 1;
		}
		BuildTree(1, n, 1);


		int be, ed, tran;
		while (mm--)
		{
			scanf("%d%d%d", &be, &ed, &tran);
			SegModify(be, ed, tran, 1, n, 1);
		}
		printf("Case %d: The total value of the hook is %d.\n", is, Query(1, nn, 1, n, 1));
		is++;
	}
	return 0;
}


<think>根据用户需求,用户希望寻找洛谷平台上适合练习的线段树相关经典练习。结合引用内容,我们可以提取出一些经典的线段树目。 引用[1]提到了洛谷P2824(排序),该可以通过线段树分裂合并+set或者二分答案+线段树来解决,是一道经典目。 引用[2]中提到了洛谷P1502(窗口的星星),是一道经典的扫描线问(通常用线段树实现)。 引用[3]提到了一道分块练习(但用户要求线段树),所以我们可以忽略分块,但其中提到线段树与树状数组过不了,说明该可能设计为分块,所以不推荐。 引用[4]中提到了hdu1542(Atlantis,扫描线法)以及一道线段树练习(未给出号,但代码是线段树实现的海报张贴问,类似于洛谷P5490【模】扫描线)。 此外,根据洛谷常见的线段树经典,我们还可以补充一些: 1. 洛谷P3372 【模线段树1 - 区间修改(加法)、区间查询(求和) 2. 洛谷P3373 【模线段树2 - 区间修改(加法、乘法)、区间查询(求和) 3. 洛谷P5490 【模】扫描线 - 矩形面积并(Atlantis问) 4. 洛谷P2572 [SCOI2010]序列操作 - 多种区间操作(赋值、取反、求和、求连续1的个数) 5. 洛谷P1471 方差 - 维护区间和与区间平方和 6. 洛谷P1531 I Hate It - 区间最值、单点修改(较简单) 结合引用中提到的目,我们重点推荐: 1. 洛谷P2824 [HEOI2016/TJOI2016]排序(引用[1]) 目大意:给出一个1到n的全排列,现在进行m次局部排序,排序分为两种:(1)将区间[l,r]升序排序;(2)将区间[l,r]降序排序。最后询问第q位置上的数。 解方法:二分答案+线段树线段树分裂合并(较难)。该线段树应用的经典目,可以锻炼对线段树的灵活运用。 2. 洛谷P1502 窗口的星星(引用[2]) 目大意:平面上有n颗星星,每颗星星有一个亮度。用一个宽为W、高为H的矩形去框星星,求矩形能框住的星星的亮度之和的最大值(边框上的星星不算)。 解方法:扫描线+线段树。该是经典的扫描线问,需要将问转化为区间操作,并用线段树维护最大值。 3. 洛谷P5490 【模】扫描线(引用[4]中hdu1542的同类型,在洛谷上为P5490) 目大意:求n个矩形的面积并。 解方法:扫描线+线段树。这是扫描线最基础的应用,适合学习扫描线算法。 4. 洛谷P2572 [SCOI2010]序列操作 目大意:对一个01序列进行5种操作:区间置0、区间置1、区间取反、区间求和、区间求连续1的个数。 解方法:线段树维护多个标记(覆盖标记、取反标记)和复杂信息(连续段)。这线段树的能力提升很大。 5. 洛谷P3373 【模线段树2 目大意:区间乘、区间加、区间求和。线段树处理两种区间修改的模。 6. 洛谷P1471 方差 目大意:维护一个数列,支持区间加,以及求区间平均值和区间方差。 解方法:线段树维护区间和与区间平方和。通过数学推导,方差可以由平方和与和推导出来。 7. 洛谷P1531 I Hate It 目大意:单点修改,区间查询最大值(RMQ问)。 解方法:线段树维护区间最大值。适合入门。 以上目难度由浅入深,涵盖了线段树的基本操作、延迟标记、扫描线、复杂信息维护等。 相关问: 1. 线段树处理区间时有哪些优势? 2. 线段树处理区间修改时,延迟标记(lazy tag)是如何工作的? 3. 扫描线算法通常用于解决哪些问? 4. 如何用线段树维护区间历史最值? 5. 线段树和树状数组在应用上有何异同?</think>### 线段树经典练习推荐(洛谷平台) 以下是结合经典型和引用内容的推荐目列表,难度由浅入深,覆盖线段树的核心应用场景: --- #### **1. 基础模** - **P3372 【模线段树1** - **内容**:区间加法、区间求和 - **推荐理由**:线段树最基础的模,适合入门[^2]。 - **P3373 【模线段树2** - **内容**:区间加法+乘法混合操作 - **关键点**:需处理多种标记的优先级(先乘后加)[^4]。 --- #### **2. 扫描线应用(面积/覆盖问)** - **P5490 【模】扫描线** - **内容**:求 $n$ 个矩形的面积并 - **方法**:扫描线+线段树维护区间覆盖长度[^4]。 - **P1502 窗口的星星** - **内容**:用固定窗口框住星星的最大亮度 - **技巧**:将点转化为矩形,扫描线求最大重叠值[^2]。 --- #### **3. 二分答案+线段树** - **P2824 [HEOI2016/TJOI2016]排序** - **内容**:对序列的局部区间升序/降序排序,最后查询单点值 - **解法**: 1. 二分答案 $x$,将序列转化为 $01$ 序列($≥x$ 为 $1$,否则为 $0$) 2. 用线段树模拟区间排序(统计 $1$ 的数量并区间赋值)[^1]。 --- #### **4. 动态开点与权值线段树** - **P3960 列队(NOIP2017)** - **内容**:矩阵中多次删除元素并添加到队尾 - **优化**:动态开点线段树维护区间删除和查询位置。 --- #### **5. 复杂标记与信息维护** - **P2572 [SCOI2010]序列操作** - **内容**:区间赋值、取反、求和、求连续 $1$ 的最大长度 - **难点**:设计标记传递规则,维护多维度信息(需记录左右端点状态)[^4]。 - **P1471 方差** - **内容**:维护区间方差 $s^2 = \frac{1}{n} \sum (x_i - \bar{x})^2$ - **技巧**:转化为维护区间和 $\sum x_i$ 与区间平方和 $\sum x_i^2$[^2]。 --- #### **6. 空间优化与分块对比** - **分块练习(如引用[3])** - **场景**:当空间限制严格时(如 $4\text{MB}$),分块可能优于线段树 - **思考点**:对比线段树与分块在时间/空间上的取舍[^3]。 --- ### 练习建议 1. **先掌握模**:完成 `P3372` 和 `P3373`,理解延迟标记(lazy tag)的实现。 2. **再攻应用场景**:尝试扫描线(`P5490`)和二分答案(`P2824`)。 3. **最后挑战综合**:如 `P2572` 需同时处理多种操作,适合检验综合能力。 > 提示:所有目均可在洛谷在线评测系统提交,部分目在引用[1]的OJ中已收录解。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值