线段树懒惰点标记更新 hduHDU - 1698 Just a Hook

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1698

题意:自行读题

解题思想:线段树原更新一次只能更新一个叶子节点,并更新此叶子结点以上所有相关的点,当一个区间做相同更新时,叶子节点以上的相关节点不断更新,时间复杂度增加。为节省时间,为每个点添加懒惰标记。自定义节点范围(l,r为求子节点区间和),懒惰点标记(lazy储存变化值),节点和(value节点区间和)。具体实现过程:当更新一个区间时,标记该区间的父亲节点为懒惰区间(祖宗节点的值不用标记,只要更新),同时更新涵盖该区间的节点,而该区间暂时懒得去更新,等下一次更新的区间与原被标记的区间有重合时,则此时将原标记区间往下标记并更新,同时父亲节点因为更新了,没懒惰了,则取消懒惰标记,即懒惰标记传给了子节点,直到重合区间可以以子节点为单位时就可以偷懒不用往下更新了,然后以相同懒惰更新的方式更新这次要更新的区间。

样例代码图解:

下图为初始化树,圈内为value值,下标为范围。

第一次更新后1-5更新为2时后的树,红色为标记点,发现1-5的子节点并没有更新,因为计算总和只和1-5这个点有关,更新这个点就行了。

第二次更新:在访问点5-9时发现5所在的1-5点被标记了,标记点下推,并更新子节点的值。

第二次5-9区间更新后的树以及标记的点。

根据图一下子就可以看出懒惰标记的意思来了,结合代码就方便多了,我画了很久的图QAQ。

具体代码如下:

#include<bits/stdc++.h>

const int maxn=100000;
using namespace std;

struct nodetree{
    int l,r;
    int value,lazy;
}tree[maxn<<2];

void pushup(int now)
{
    tree[now].value=tree[now<<1].value+tree[now<<1|1].value;
}

void build(int l,int r,int n)
{
    tree[n].l=l;
    tree[n].r=r;
    tree[n].lazy=0;
    if(l==r)
    {
        tree[n].value=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,n<<1);
    build(mid+1,r,n<<1|1);
    pushup(n);
}
void pushdown(int n)
{
    if(tree[n].lazy!=0)
    {
        tree[n<<1].lazy=tree[n<<1|1].lazy=tree[n].lazy;
        tree[n<<1].value=(tree[n<<1].r-tree[n<<1].l+1)*tree[n<<1].lazy;
        tree[n<<1|1].value=(tree[n<<1|1].r-tree[n<<1|1].l+1)*tree[n<<1|1].lazy;
        tree[n].lazy=0;
    }
}
void update(int l,int r,int le,int ri,int n,int va)
{
    if(r<le||l>ri)
        return;
    if(l>=le&&r<=ri)
    {
        tree[n].lazy=va;
        tree[n].value=tree[n].lazy*(tree[n].r-tree[n].l+1);
        return;
    }
    pushdown(n);
    int mid=(l+r)>>1;
    if(mid>=le) update(l,mid,le,ri,n<<1,va);
    if(mid<ri) update(mid+1,r,le,ri,n<<1|1,va);
    pushup(n);
}
int main()
{
    int T;
    while(~scanf("%d",&T))
    {
        int count=1;
        while(T--)
        {
            int n,t,l,r,va;
            scanf("%d",&n);
            build(1,n,1);
            scanf("%d",&t);
            while(t--)
            {
                scanf("%d %d %d",&l,&r,&va);
                update(1,n,l,r,1,va);
            }
            printf("Case %d: The total value of the hook is %d.\n",count++,tree[1].value);
        }
    }
    return 0;
}

  最后说一下点的value是通过数学计算算出来的。

原文地址:https://www.cnblogs.com/wwq-19990526/p/10311109.html

时间: 2024-10-08 17:14:26

线段树懒惰点标记更新 hduHDU - 1698 Just a Hook的相关文章

hdu 1698 Just a Hook(线段树之 成段更新)

Just a Hook                                                                             Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description In the game of DotA, Pudge's meat hook is actually the mos

HDOJ--4893--Wow! Such Sequence!【线段树+单点、区间更新】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 题意:给你一个长度n的数列,初始都为0,有三种操作,第一种给第k个位置的数加d,第二种是查询区间 [l , r] 的总和,第三种是使区间 [l , r] 的值改为离它最近的那个斐波那契数的值. 我刚开始用sum数组存储节点的值,第三种操作是个区间更新,但是区间更新的值不一样,我就想当然的搜到最底部的节点来处理更新,果断T了.后来想了想,其实可以在节点上再加一个信息,就是这个值下次进行第三种操作要变

uva 11992 线段树对矩阵进行更新查询

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3143 把矩阵变成一行,然后计算位置,lrj给了线段树数组做法 但是我做的线段树空间过大,直接爆掉,所以换方法了 主要还是测试自己的线段树区间更新的模板 各种RE+WA之后AC,,,,, 做的时候出现的几个错误: 1.行和列弄错 2.build初始化的时候,mmin mmax 都初始化为0才对

POJ 3468-A Simple Problem with Integers(线段树:成段更新,区间求和)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 62228   Accepted: 19058 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

POJ2886 Who Gets the Most Candies? 【线段树】+【单点更新】+【模拟】+【反素数】

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9416   Accepted: 2868 Case Time Limit: 2000MS Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise o

HDU2795 Billboard 【线段树】+【单点更新】

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9632    Accepted Submission(s): 4286 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

POJ2828 Buy Tickets 【线段树】+【单点更新】+【逆序】

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 12296   Accepted: 6071 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year wa

线段树-区间单个点更新-区间和-区间最大

线段树: 图中的元素[a,b]表示该节点存储的值是在a到b内的结果(最大值或者和).其根节点为c的话,其下面两个子树节点的序号为 c*2 和 c*2+1 区间最大值 题目: Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有时候需要更新某位同学的成绩. Input 本题目包含多组测试,请处理到文件结束. 在每