HDU - 1698 - Just a Hook(线段树基础)

#HDU - 1698 - Just a Hook
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.

HDU - 1698 - Just a Hook(线段树基础)_第1张图片

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下标传递给孩子节点。这样说起来可能有点抽象,画个图,或者结合代码思考一下就明白了,下面上代码:

#include 
#include 
using namespace std;
const int maxn = 4e5 + 5;
int a[maxn];

struct node
{
    int l, r, val, laz;
}p[maxn];

void pushup(int cur)
{
    p[cur].val = p[cur << 1].val + p[(cur << 1) | 1].val;
}

void build(int l, int r, int cur)
{
    int m = (l + r) / 2;
    p[cur].val = p[cur].laz = 0;
    p[cur].l = l;   p[cur].r = r;
    if(l == r)
    {
        p[cur].val = 1;
        return ;
    }
    build(l, m, 2 * cur);
    build(m + 1, r, 2 * cur + 1);
    pushup(cur);
}

void pushdown(int cur)
{
    if(!p[cur].laz) return ;
    //把laz传给孩子节点,并把自身的标记去掉
    p[cur << 1].laz = p[cur].laz;
    p[(cur << 1) | 1].laz = p[cur].laz;
    p[cur].laz = 0;
    
    int l = p[cur << 1].l, r = p[cur << 1].r;
    p[cur << 1].val = (r - l + 1) * p[cur << 1].laz;
    
    l = p[(cur << 1) | 1].l, r = p[(cur << 1) | 1].r;
    p[(cur << 1) | 1].val = (r - l + 1) * p[cur << 1].laz;
}

void update(int ul, int ur, int cur, int val)
{
    int l = p[cur].l, r = p[cur].r;
    int m = (l + r) / 2;
    if(ul <= l && r <= ur)
    {
        p[cur].laz = val;
        p[cur].val = val * (r - l + 1);
        return ;
    }
    if(ul <= m)
    {
        pushdown(cur);
        update(ul, ur, cur << 1, val);
    }
    if(ur > m)
    {
        pushdown(cur);
        update(ul, ur, (cur << 1) | 1, val);
    }
    pushup(cur);
}

int main()
{
    int t;
    scanf("%d", &t);
    for(int test = 1; test <= t; test++)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        memset(p, 0, sizeof(p));
        build(1, n, 1);
        for(int i = 0; i < m; i++)
        {
            int x, y, a;
            scanf("%d%d%d", &x, &y, &a);
            update(x, y, 1, a);
        }
        printf("Case %d: The total value of the hook is %d.\n", test, p[1].val);
    }
    return 0;
}

你可能感兴趣的:(数据结构)