Just a Hook
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.
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.
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.
分析:本题是线段树区间更新,引入了“延迟标记”概念。(一下解释是网上copy的)
区间更新是指更新某个区间内的叶子节点的值,因为涉及到的叶子节点不止一个,而叶子节点会影响其相应的非叶父节点,那么回溯需要更新的非叶子节点也会有很多,如果一次性更新完,操作的时间复杂度肯定不是O(lgn),例如当我们要更新区间[0,3]内的叶子节点时,需要更新出了叶子节点3,9外的所有其他节点。为此引入了线段树中的延迟标记概念,这也是线段树的精华所在。
延迟标记:每个节点新增加一个标记,记录这个节点是否进行了某种修改(这种修改操作会影响其子节点),对于任意区间的修改,我们先按照区间查询的方式将其划分成线段树中的节点,然后修改这些节点的信息,并给这些节点标记上代表这种修改操作的标记。在修改和查询的时候,如果我们到了一个节点p,并且决定考虑其子节点,那么我们就要看节点p是否被标记,如果有,就要按照标记修改其子节点的信息,并且给子节点都标上相同的标记,同时消掉节点p的标记。
AC代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+10;
int sum[maxn<<2]; //存和数组
int cnt[maxn<<2]; //标记
int N,Q;
void build(int l,int r,int rt){ //建树
cnt[rt]=0;
if(l==r){
sum[rt]=1;
return ;
}
int m=(r+l)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void Down(int rt,int len){ //向下推一级 ,同时消去节点rt的标记
if(cnt[rt]){
cnt[rt<<1]=cnt[rt<<1|1]=cnt[rt];
sum[rt<<1]=(len-(len>>1))*cnt[rt];
sum[rt<<1|1]=(len>>1)*cnt[rt];
cnt[rt]=0;
}
}
void Update(int x,int y,int z,int l,int r,int rt){
if(x<=l && y>=r){
sum[rt]=(r-l+1)*z;
cnt[rt]=z;
return ;
}
Down(rt,r-l+1);
int m=(l+r)>>1;
if(x<=m)
Update(x,y,z,l,m,rt<<1);
if(y>m)
Update(x,y,z,m+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int main(){
int T;
scanf("%d",&T);
int count=0;
while(T--){
scanf("%d%d",&N,&Q);
build(1,N,1);
int x,y,z;
for(int i=0;i<Q;i++){
scanf("%d%d%d",&x,&y,&z);
Update(x,y,z,1,N,1);
}
printf("Case %d: The total value of the hook is %d.\n",++count,sum[1]);
}
return 0;
}