欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HDU1698 Just a Hook(线段树+成段更新+lazy标记)

程序员文章站 2022-06-16 08:47:39
...

题目:

Just a Hook

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


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.

HDU1698 Just a Hook(线段树+成段更新+lazy标记)


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   |   We have carefully selected several similar problems for you:  1542 1255 1828 1540 3397 
 

Statistic | Submit | Discuss | Note
思路:

先说题意,有t组数据,接下来一个n,代表是从[1~n]的区间,然后有m行操作,每行有一组a,b,c,代表把[a,b]区间的所有元素的值改变成c,最后题目求的是从[1~n]的区间和(最初这个区间的每个元素的值为1)


这道题看了好久,用来理解懒惰标记,关于懒惰标记,可以看这个:线段树延迟标记精讲



延迟标记:每个节点新增加一个标记,记录这个节点是否进行了某种修改(这种修改操作会影响其子节点),对于任意区间的修改,我们先按照区间查询的方式将其划分成线段树中的节点,然后修改这些节点的信息,并给这些节点标记上代表这种修改操作的标记。在修改和查询的时候,如果我们到了一个节点p,并且决定考虑其子节点,那么我们就要看节点p是否被标记,如果有,就要按照标记修改其子节点的信息,并且给子节点都标上相同的标记,同时消掉节点p的标记。



我自己的理解延迟标记就是比如你要把[0,2]区间的值都加上1,你找到代表[0,2]的非叶子节点,给这里加一个标记,标记为2,然后就不管了,等我们下一次,需要对它的子节点进行操作时,我们发现[0,2]这个节点有标记,那么我们就按照我标记的值,把这个标记往下一层传递,并且更新子节点的值,然后在子节点那里也放置一个同样的标记,把当前位置的标记变成0.所以我们定义了一个pushdown()函数,先把标记传递给子节点,然后再更新左右子树的和

设置一个懒惰标记的好处就是可以降低时间,等到用的时候再更新。


代码:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <string>
#include <set>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 10000007
#define debug() puts("what the fuck!!!")
#define N 111111
#define M 1000000
#define ll long long
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int lazy[4*N];//用来标记,为0表示没有被标记,以要更新的值来做标记
int sum[4*N];//sum[i]代表以i为根节点的和
void pushup(int rt)//向上更新和
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];

}
void pushdown(int rt,int m)//对某一个区间进行改变,如果被标记了,在查询的时候就得把改变传给子节点,因为查询的并不一定是当前区间
{
    //m为区间长度
    if(lazy[rt])
    {
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];//传递给子节点
        //更新左儿子和右儿子的和
        sum[rt<<1]=(m-(m>>1))*lazy[rt];
        sum[rt<<1|1]=(m>>1)*lazy[rt];
        lazy[rt]=0;//取消对当前节点的标记
    }
}
void build(int l,int r,int rt)
{
    lazy[rt]=0;//初始化左右节点都没有被标记
    sum[rt]=1;//初始值都为1
    if(l==r) return;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        lazy[rt]=c;
        sum[rt]=c*(r-l+1);//更新代表某个区间的节点和
        //printf("sum[%d]=%d,L=%d,R=%d,c=%d,lazy[rt]=%d\n",rt,sum[rt],L,R,c,lazy[rt]);
        return;
    }
    pushdown(rt,r-l+1);//向下传递
    int m=(l+r)>>1;
    if(L<=m)  update(L,R,c,lson);
    if(R>m)   update(L,R,c,rson);
    pushup(rt);//向上传递更新和
}
int n,m,t,a,b,c,q=1;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        build(1,n,1);//建立线段树
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            update(a,b,c,1,n,1);//更新区间
        }
        printf("Case %d: The total value of the hook is %d.\n",q++,sum[1]);
    }
    return 0;
}