线段树2——懒标记

学完了线段树的基础知识(建树,修改,查询等操作)后,来看看下面这题

注:原题链接:https://www.luogu.org/problemnew/show/P3372

读完这题,是不是有跃跃欲试的感觉?

1)查询区间和   简单

2)区间修改??? 

for(int i=l;i<=r;i++)add(1,i,val);

所以,智障的我就写出了这样的代码

然后,稳稳的TLE

我们来分析一下上述代码的时间复杂度

1. 查询操作 O ( nlogn )

2. 区间修改 每一次单点修改O(n),总共n次,O(nlogn)

100000*100000*log(100000)  TLE!!!

所以,这时候,我们需要——

懒标记


1.懒标记用途

懒标记的作用是,在区间修改的时候,我们在需要修改的区间放个标记,下次要用的时候再打开。

这样可以节省大量的时间,可以把区间修改的时间复杂度降至O(log(n))

2.懒标记的实现

上述做法固然解决了区间修改的问题

但是——

我们要查询的时候怎么办,总不能

cout<<"I can‘t do it"<<endl;

我们需要——

把懒标记拆了

if(tree[root].l==l&&tree[root].r==r)// 找到区间
        return tree[root].val+tree[root].tag*(r-l+1);// 计算并返回答案
if(tree[root].tag)//如果有懒标记
{
    tree[root*2].tag+=tree[root].tag;
    tree[root*2+1].tag+=tree[root].tag;//下传懒标记
    tree[root].val+=(tree[root].r-tree[root].l+1)*tree[root].tag;//计算答案
    tree[root].tag=0;//清空标记
}

这样,我们就完成了查询和清除懒标记的工作。

回过头谈谈修改

void add(int root,int l,int r,int val)
{
    if(tree[root].l==l&&tree[root].r==r)
    {
        tree[root].tag+=val;
        return;
    }
    tree[root].val+=(r-l+1)*val;
    if(tree[root].mid>=r)add(root*2,l,r,val);
    else if(tree[root].mid<l)add(root*2+1,l,r,val);
    else add(root*2,l,tree[root].mid,val),add(root*2+1,tree[root].mid+1,r,val);
}

找到区间放标记,回头再来查答案

3.线段树经典题目

luogu P1886 滑动窗口

其实,这题是单调队列的题目

但用线段树依旧能过(只要你的线段树常数不大)

代码:

// luogu-judger-enable-o2
#include<bits/stdc++.h>

using namespace std;

int n,k;
struct T{
    int l,r,mid,v;
}t1[4000005],t2[4000005];

void build(int root,int l,int r)
{
    int mid=(l+r)/2;
    t1[root].l=l,t1[root].r=r,t1[root].mid=mid;
    t2[root].l=l,t2[root].r=r,t2[root].mid=mid;
    if(l==r)
    {
        scanf("%d",&t1[root].v);
        t2[root].v=t1[root].v;
        return;
    }
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
    t1[root].v=max(t1[root*2].v,t1[root*2+1].v);
    t2[root].v=min(t2[root*2].v,t2[root*2+1].v);
}

int query(int a,int b,int root,int flag)
{
    int l=t1[root].l,r=t1[root].r;
    int mid=(l+r)/2;
    if(a==l&&b==r)return flag==1?t1[root].v:t2[root].v;
    if(b<=mid)return query(a,b,root*2,flag);
    else if(a>mid)return query(a,b,root*2+1,flag);
    else return flag==1?max(query(a,mid,root*2,flag),query(mid+1,b,root*2+1,flag)):min(query(a,mid,root*2,flag),query(mid+1,b,root*2+1,flag));
}

int main()
{
    scanf("%d%d",&n,&k);
    build(1,1,n);
    for(int f=0;f<=1;f++)
    {
        for(int i=1;i<=n-k+1;i++)
            printf("%d ",query(i,i+k-1,1,f));
        printf("\n");
    }
    return 0;
}

简单的线段树练手题。

顺便说下单调队列的方法

#include<bits/stdc++.h>

#define top front

using namespace std;

int n,k;
int a[1000005];
deque<int>q;

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=k;i++)
    {
        while(!q.empty()&&a[q.back()]>a[i])q.pop_back();
        q.push_back(i);
    }
    cout<<a[q.front()]<<‘ ‘;
    for(int i=k+1;i<=n;i++)
    {
        while(!q.empty()&&a[q.back()]>a[i])q.pop_back();
        q.push_back(i);
        while(!q.empty()&&q.front()<=i-k)q.pop_front();
        cout<<a[q.front()]<<‘ ‘;
    }
    cout<<endl;
    while(!q.empty())q.pop_front();
    for(int i=1;i<=k;i++)
    {
        while(!q.empty()&&a[q.back()]<a[i])q.pop_back();
        q.push_back(i);
    }
    cout<<a[q.front()]<<‘ ‘;
    for(int i=k+1;i<=n;i++)
    {
        while(!q.empty()&&a[q.back()]<a[i])q.pop_back();
        q.push_back(i);
        while(!q.empty()&&q.front()<=i-k)q.pop_front();
        cout<<a[q.front()]<<‘ ‘;
    }
    cout<<endl;

    return 0;
} 

好了,学完了懒标记,遇到题目直接用线段树吧!

 

原文地址:https://www.cnblogs.com/Robin20050901/p/9876321.html

时间: 2024-10-21 12:12:58

线段树2——懒标记的相关文章

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

UVa 11992 Fast Matrix Operations(线段树双懒操作,二维转一维)

题意:给个r*c的矩形,三种操作,将一个子矩形权值+v,将一个子矩阵权值赋值为v,查询一个子矩阵sum,max,min.起初矩阵权值为0,保证r<=20,r*c<=1e6,操作次数不超过10000 链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18697 题解:将二维转一维,设当前点为(x,y),则它在线段树上的点为(x-1)*c+y,由于行不超过20行,不妨枚举每一行,去操作.对于一维的线段树,要进行赋值,加法

线段树初步&amp;&amp;lazy标记

线段树 一.概述: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩. 二.基本操作: 1

POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每次更新异或1就可以. 熟悉线段树成段更新就很简单了,最初姿势不对一直wa,还是没有彻底理解lazy标记啊. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace st

【BZOJ-2892&amp;1171】强袭作战&amp;大sz的游戏 权值线段树+单调队列+标记永久化+DP

2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] Description 在一个没有冬马的世界里,经历了学园祭后的春希着急着想要见到心爱的雪菜.然而在排队想见雪菜的fans太多了,春希一时半会凑不到雪菜面前. 作为高帅富,这样的问题怎么能难倒春希?春希从武也手中拿到了取自金闪闪宝库里的多啦A梦的传话筒,并且给每一个排队的fans都发了一个传话筒. 于

算法模板——线段树之Lazy标记

一.前言 前面我们已经知道线段树能够进行单点修改和区间查询操作(基本线段树).那么如果需要修改的是一个区间该怎么办呢?如果是暴力修改到叶子节点,复杂度即为\(O(nlog_n)\),显然是十分不优秀的.那么我们能不能向区间查询一样把复杂度降到\(O(log_n)\)呢? 二.算法流程 线段树肯定是兹瓷\(O(log_n)\)修改的,否则发明它有何用处?所以,我我们现在需要知道,如何快速进行区间修改操作.首先,我们回顾下终止节点 假定我要在这个图上修改区间[2,8],我只要修改掉图上所有的终止节点

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

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 题意:自行读题 解题思想:线段树原更新一次只能更新一个叶子节点,并更新此叶子结点以上所有相关的点,当一个区间做相同更新时,叶子节点以上的相关节点不断更新,时间复杂度增加.为节省时间,为每个点添加懒惰标记.自定义节点范围(l,r为求子节点区间和),懒惰点标记(lazy储存变化值),节点和(value节点区间和).具体实现过程:当更新一个区间时,标记该区间的父亲节点为懒惰区间(祖宗节点的值不用标记

POJ 2777 count color(线段树,lazy标记)

这里有一个思想:我们在更新的时候不必要更新到叶子节点,只要更新到当前区间包含线段树区间即可. 设计一个标志位,更新到此. A Simple Problem with Integers 也是一个类似的题目 设计两个函数 push_down 将结点信息传递到下层节点(inc, sub,) push_up      将下层节点信息反馈到上层(max,min,count) #include <map> #include <set> #include <queue> #inclu

SDUT2880 Devour Magic 线段树(set+add标记)

Devour Magic Time Limit: 2000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 In Warcraft III, Destroyer is a large flying unit that must consume magic to sustain its mana. Breaking free of the obsidian stone that holds them, these monstrous creatures roar