题干:

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.

题目大意:

在DOTA里有一个英雄 屠夫,他有一个肉钩,巨长,然后默认都是黄铜做的,每一节的价值都为1。然后他要改变钩子连续链节,换成别的材质。然后题目开始输入样例的个数,然后是钩子的链节数,接下来是操作的次数。后面就是更改了,1是黄铜,2是白银,3是金,价值也是这个数。

解题报告:

     区间覆盖更新,区间和查询。这个题目用到了线段树对区间的更改,相对于单点改值,这个需要有一个pushdown函数。这个题目的话,我们现想一下更改区间的方法,最麻烦的方法就是从给出区间左端点一直遍历修改到右端点,但是这样的话相对来说时间复杂度有点高,难以接受,还有可能TLE。 
所以大佬们就想出来了,在节点当中加一个元素,那就是laz(lazy)元素,这个元素在建树的时候都赋值为零,表示还没有进行改值,然后改值更新的时候,直接在能够被完全包含的区间上进行修改,因为是区间改值,并且修改的值都相同,所以就是修改值乘以区间长度给父节点作出相应处理就可以了,而不是一直改下去改到每一个叶节点,取而代之的是在该节点上记录一下laz,代表这个区间内的值有所改变,但是还没有向分支传递。然后查询的时候,如果需要这个区间内子区间的值的话,那么就借助pushdown函数将laz下标传递给孩子节点。这样说起来可能有点抽象,画个图,或者结合代码思考一下就明白了。参考博客​​​​​​​

AC代码:

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 100000 + 5;	
int n;
int a[MAXN];
struct TREE {
	int l,r;
	int val;
	int laz;	
} tree[4*MAXN];
void pushup(int cur) {
	tree[cur].val = tree[2*cur].val + tree[2*cur + 1].val; 
}
void build(int l ,int r,int cur) {
	if(l == r) {
		tree[cur].l = tree[cur].r = l;//写成tree[r].r 了。。 
		tree[cur].val = a[l];
		tree[cur].laz = 0;
		return ;//这步return必须加!不然就无限递归了。这就是为什么写递归函数,要将出口写在最前面,就是,不给他再次进入递归函数的机会! 
	}
	int m = (l+r)/2;
	tree[cur].l = l;
	tree[cur].r = r;
//	tree[cur].val = 0;//加不加均可。 
	build(l,m,2*cur);
	build(m+1,r,2*cur + 1);
	pushup(cur);
}
void pushdown(int cur,int l,int r) {
	int m = (l+r)/2;
	if(tree[cur].laz !=0) {
		tree[2*cur].val = (m-l+1) *tree[cur].laz;
		tree[2*cur].laz = tree[cur].laz;
		tree[2*cur + 1].val = (r-m) * tree[cur].laz;
		tree[2*cur + 1].laz = tree[cur].laz;
		tree[cur].laz = 0;
	}
}
//pl-pr为查询区间,l和r为树种 当前cur下标 
int query2(int pl,int pr,int l,int r,int cur) {
	if(pl<=l && pr>=r) return tree[cur].val; 
	pushdown(cur,l,r);
	int m = (l+r)/2;
	int res = 0;
	if(pl <= m) res += query2(pl,pr,l,m,2*cur);
	//下面这里是if啊!!不是else!!! 
	if(pr >= m+1) res += query2(pl,pr,m+1,r,2*cur + 1);
	return res;
}
void update2(int pl,int pr,int val,int l,int r,int cur) {
	if(pl<=l && pr >= r) {
		tree[cur].val = (r-l+1) * val;
		tree[cur].laz =val;
		return ;
	}
	pushdown(cur,l,r);
	int m = (l + r) / 2;
	if(pl <= m) update2(pl,pr,val,l,m,2*cur);
	if(pr >= m + 1) update2(pl,pr,val,m+1,r,2*cur+1);
	pushup(cur);
}
int main()
{
	int t,m;
	int iCase = 0;
	int tmp1,tmp2;
	int op;
	cin>>t;
	while(t--) {
		printf("Case %d: ",++iCase);
		scanf("%d",&n);
		for(int i = 1; i<=n; i++ ) {
			a[i] = 1;
		}
		memset(tree,0,sizeof(tree));
		build(1,n,1);
//		for(int i = 1; i<=100; i++) printf("%d ",tree[i].val);
//		printf("\n");
		scanf("%d",&m);
		while(m--) {
			scanf("%d%d%d",&tmp1,&tmp2,&op);
			update2(tmp1,tmp2,op,1,n,1);
//			for(int i = 1; i<=100; i++) printf("%d ",tree[i].val);
//			printf("\n");
		}
		printf("The total value of the hook is %d.\n",query2(1,n,1,n,1));
//		printf("%d %d ",tree[1].l,tree[1].r); 
//		for(int i = 1; i<=100; i++) printf("%d ",tree[i].val);
//		printf("\n");
	}	
	return 0 ;
 }