线段树多lazy-tag(两个)

【题解】「AHOI2009」维护序列(线段树) 题面 【题目描述】 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为NNN的数列,不妨设为a1,a2,…,aNa_1,a_2,…,a_Na1​,a2​,…,aN​。有如下三种操作形式: (1)(1)(1)把数列中的一段数全部乘一个值; (2)(2)(2)把数列中的一段数全部加一个值; (3)(3)(3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模PPP的值。 ... 阅读详情

线段树多lazy-tag(两个)

题意:有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式:
(1)把数列中的一段数全部乘一个值;
(2)把数列中的一段数全部加一个值;
(3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
解题思路:
结构体定义:

typdef long long ll;
struct Node{
    int l,r;
    ll sum;
    ll mul,add;
}tree[4*MAXN];

用两个lazy-tag标记: mul , add ,其中mul初始化为1,add初始化为0
由于要进行的lazy-tag标记很多,于是我们对它们设定优先级别,很明显乘法的优先级高于加法,于是我们便可以这样处理,例如
对于某个区间我们如果先对它进行加x然后再乘y的操作就可以化为
( [a,b] + x ) * y = [a,b] * y + x * y
对于某个区间我们如果先对它进行乘x然后加y的操作就是
( [a,b] * x ) + y = [a,b] * x + y
所以
(1)当对某个区间进行乘v时

tree[node].mul = ( tree[node].mul * v ) % p;
tree[node].add = ( tree[node].add * v ) % p;
tree[node].sum = ( tree[node].sum * v ) % p;

(2)当对某个区间进行加v时

tree[node].add = ( tree[node].add + v ) % p;
tree[node].sum = ( tree[node].sum + v * ( tree[node].r - tree[node].l + 1 ) ) % p;

(3)PushDown操作(先传递乘,再传递加)

void PushDown(int node){
    if (tree[node].mul==1 && tree[node].add==0)
        return; 
    tree[node*2].mul=(tree[node*2].mul*tree[node].mul)%p; 
    tree[node*2+1].mul=(tree[node*2+1].mul*tree[node].mul)%p;
    tree[node*2].add=(tree[node*2].add*tree[node].mul+tree[node].add)%p;
    tree[node*2+1].add=(tree[node*2+1].add*tree[node].mul+tree[node].add)%p;
    tree[node*2].sum=(tree[node*2].sum*tree[node].mul+tree[node].add*(tree[node*2].r-tree[node*2].l+1))%p;
    tree[node*2+1].sum=(tree[node*2+1].sum*tree[node].mul+tree[node].add*(tree[node*2+1].r-tree[node*2+1].l+1))%p;
    tree[node].mul=1;
    tree[node].add=0;
}

参考代码:

#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long ll;
const int MAXN = 100000+5;
ll p;
struct Node{
    int l,r;
    ll sum;
    ll mul,add;
}tree[4*MAXN];
void build(int node,int l,int r){
    tree[node].l=l,tree[node].r=r;
    tree[node].mul=1,tree[node].add=0;
    if (l==r){
        scanf("%lld",&tree[node].sum);
        tree[node].sum%=p;  //1
        return;
    }
    int mid=(l+r)/2;
    build(node*2,l,mid);
    build(node*2+1,mid+1,r);
    tree[node].sum=(tree[node*2].sum+tree[node*2+1].sum)%p;
}
void PushDown(int node){
    if (tree[node].mul==1 && tree[node].add==0)
        return;

    tree[node*2].mul=(tree[node*2].mul*tree[node].mul)%p;
    tree[node*2+1].mul=(tree[node*2+1].mul*tree[node].mul)%p;

    tree[node*2].add=(tree[node*2].add*tree[node].mul+tree[node].add)%p;
    tree[node*2+1].add=(tree[node*2+1].add*tree[node].mul+tree[node].add)%p;

    tree[node*2].sum=(tree[node*2].sum*tree[node].mul+tree[node].add*(tree[node*2].r-tree[node*2].l+1))%p;
    tree[node*2+1].sum=(tree[node*2+1].sum*tree[node].mul+tree[node].add*(tree[node*2+1].r-tree[node*2+1].l+1))%p;

    tree[node].mul=1;
    tree[node].add=0;

}
void Add(int node,int l,int r,ll v){
    if (l>tree[node].r || r<tree[node].l)
        return;
    if (l<=tree[node].l && tree[node].r<=r){
        tree[node].add=(tree[node].add+v)%p;
        tree[node].sum=(tree[node].sum+v*(tree[node].r-tree[node].l+1))%p;
        return;
    }
    if (tree[node].l==tree[node].r)
        return;
    PushDown(node);
    Add(node*2,l,r,v);
    Add(node*2+1,l,r,v);
    tree[node].sum=(tree[node*2].sum+tree[node*2+1].sum)%p;
}
void Mul(int node,int l,int r,ll v){
    if (l>tree[node].r || r<tree[node].l)
        return;
    if (l<=tree[node].l && tree[node].r<=r){
        tree[node].mul=(tree[node].mul*v)%p;
        tree[node].add=(tree[node].add*v)%p;
        tree[node].sum=(tree[node].sum*v)%p;
        return;
    }
    if (tree[node].l==tree[node].r)
        return;
    PushDown(node);
    Mul(node*2,l,r,v);
    Mul(node*2+1,l,r,v);
    tree[node].sum=(tree[node*2].sum+tree[node*2+1].sum)%p;
}
ll query(int node,int l,int r){
    if (l>tree[node].r || r<tree[node].l)
        return 0;
    if (l<=tree[node].l && tree[node].r<=r){
        return tree[node].sum;
    }
    if (tree[node].l==tree[node].r)
        return 0;
    PushDown(node);
    return (query(node*2,l,r)+query(node*2+1,l,r))%p;
}
void Debug(int node){
    for (int i=0;i<4*node;i++)
        cout<<tree[i].sum<<" ";
    cout<<endl;
}
int main(){
    int n,m;
    int tag,a,b;
    ll v;
    while (~scanf("%d%lld",&n,&p)){
        build(1,1,n);
        scanf("%d",&m);
        //Debug(n);
        while (m--){
            scanf("%d",&tag);
            if (tag==3){
                scanf("%d%d",&a,&b);
                printf("%lld\n",query(1,a,b)%p);
            }
            if (tag==1){
                scanf("%d%d%lld",&a,&b,&v);
                Mul(1,a,b,v);
            }
            if (tag==2){
                scanf("%d%d%lld",&a,&b,&v);
                Add(1,a,b,v);
            }
            //Debug(n);
        }
    }
    return 0;
}
线段树及Lazy-Tag 一:线段树 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(log2N)。 线段树的每个节点都表示一个区间[L, R],对于一个线段树的区间: 若L < R,则必能被分为[L, M]和[M+1, R],其中M = (L + R) / 2。 若L = R,则为 阅读详情

相关推荐

线段树Lazy Tag原理深度解析:从区间更新优化到延迟计算思想

在处理大规模数据区间更新与查询问题时,暴力遍历方法面临严重的性能瓶颈。线段树通过分治与预处理思想,将区间查询复杂度优化至对数级别,但其核心挑战在于如何高效支持区间修改。Lazy Tag(延迟标记)技术应运而生,它本质上是一种延迟计算策略:将区间更新的影响暂存在父节点标记中,仅在需要访问子节点数据时才进行下推,从而将区间更新复杂度也降至O(log n)。这种设计体现了用空间换时间的经典权衡,其关键在于操作必须满足可叠加性与可传递性,如区间加法、赋值等。从工程实践看,Lazy Tag的思想广泛存在于数据库事务日

weixin_30256901的博客 413

线段树详解

线段树

good good study, day day up! 1317

lazytag:延迟加载自定义元素及其样式,甚至无需考虑

懒惰标签 延迟加载自定义元素及其样式,甚至无需考虑它。 < script > // you can have many lazyTag invokes per page lazyTag ( { // an optional *Array* of custom elements names or RegExp // to consider: any other custom element will be ignored only : [ / ^ io- / ] , // an optional *Array* of custom elements to ignore // if `only` is used, this list is ignored ignore : [ 'third-parts' , 'pre-loaded' , / -heresy $ / ]

线段树(lazy用法)

在上一篇中,我们讨论了线段树的基础用法,其中我们对于线段树的修改,仅仅限制于对于线段树的点的修改,而不是对于某一个一段区间的修改。 那么我们现在来想想如果对于线段树的一段区间来进行修改的话,如果我们还是来对线段树的每一个点都进行修改的话,那么,假设我们需要修改m个点,其时间复杂度岂不是为O(log(n))了,那么我们所需要的少的时间复杂度的要求就没有达成,为此,lazy数组应运而生,来解决这个问题。 首先我们来认识一下lazy:如果当前区间被需要修改的目标区间完全覆盖,打一个标记。如果下一次的查询或者更改包

malloch的博客 2765

Navcat最新版的激活和安装教程(全网最靠谱,最快捷的方式)

现在最新版本navcat已经出到了16.3了,并且新版navcat也支持连接redis和图标等更多样化的功能,但是比较头疼的一件事就是,只能试用14天。那么接下来小编教大家如何用最简单的方式使用最新版navcat16.

weixin_50737119的博客 2万+

阿里云天池大数据长期赛:金融风控-贷款违约预测(含代码)

本次比赛让自己在大数据的处理流程上有了更明确的认知,从数据清洗、特征工程、数据建模,每一个过程都能学到很多经验和知识,值得去历练。

weixin_46685991的博客 1万+

线段树的懒标记与应用

本文主要讲了线段树的Lazy-tag技术和一道例题,建议自己要多练习线段树的题目。

m0_52711790的博客 2895

PADS VX2.7学习记录05-PADS Layout设计文件Gerber等输出整理

在“PDF Document”栏中,依次选中除REF-TOP和REF-BOT之外的文件,单击图标,将其余PDF Document文件进行删除,如图所示。然后单击【生成PDF】按钮,即可创建一份PDF格式的位号图。

tianpu2320959696的博客 1025

数据结构:线段树

线段树的节点tree[i]记录了区间i的值,那么可以再定义一个tag[i],用它统一记录区间i的修改,而不是一个个地修改区间内的每个元素,这个方法称为Lazy-Tag(懒惰标记或延迟标记)。区间修改时给p打了tag标记,接下来就把tag[p]传给左右子树,然后把tag[p]清零。使用Lazy-Tag方法时,若修改的是一个线段区间,就只对这个线段区间进行整体上的。修改,其内部每个元素的内容先不做修改,只有当这个线段区间的一致性被破坏时,才把变。区间i的Lazy操作,用tag[i]记录。

2302_79366101的博客 1057

【ArcGIS Pro微课1000例】0047:深度学习--棕榈树提取全流程

对汤加科洛瓦伊种植园每棵棕榈树的健康状况进行清查和评估,这需要花费大量的时间和劳动力。为简化此过程,将在 ArcGIS Pro 中使用深度学习模型来识别树木,然后根据植被绿度的测量值计算其健康状况。第一步是找到显示汤加科洛瓦伊的影像,该影像具有足够精细的空间和光谱分辨率来识别树木。获得此影像后,将创建训练样本并将其转换为可供深度学习模型使用的格式。为了让模型识别出它的查找任务,需要定义棕榈树的影像,以便识别相似的像素和树木大小。

智慧空间实验室 2207

YOLOv13改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进

1️⃣ 已更新种不同的改进方案,专栏内的每篇文章皆,均可顺利运行。2️⃣ 订阅专栏即可进群获取以及从的各种答疑内容。3️⃣ 全新的YOLOv13改进专栏,,只为更好的满足论文发表的要求。专栏内容,专栏实时评分,全网最高,质量保证。🎫。。

Limiiiing的博客 9156

20-12-17随笔---深入理解线段树lazy_tag操作

第二十一次CSP认证第五题 深入理解线段树lazy_tag操作

萍水相逢,尽是他乡之客 296

从苏宁电器到卡巴斯基(第二部)第01篇:我在卡巴的日子 I

聊聊行业薪酬 我相信不论是谁,如果是入职一家新的公司,那么他最想知道的一件事情就是待遇情况了。这里既包含每月实际能到手多少钱,又包括五险一金是否齐全以及是按照高标准还是低标准缴纳。另外,如果是入职IT公司,还会在意年终奖有多少,毕竟某些富裕的IT企业,每到年末就会以此制造新闻来博取大家的关注,以彰显自身的实力。 一言以蔽之,待遇问题也就是年收入究竟会有多少,也是我们进入职场的人喜欢相互打听的问题。比如我研究生那届最厉害的一位同学,签了A公司的算法岗位,年薪30W+(税前,下同),在当时的我看来就是天价了

Gleam的专栏 1225

P3373线段树模板

线段树,p3373,这题总共有三种操作:将某区间每一个数乘上 x将某区间每一个数加上 x求出某区间每一个数的和add*multi子树的值=子树的值*父节点的multi的标记数+父节点的add标记数*区间大小得到上述代码只是为了做一个简单讲述,因为题目要求有取模运算,以及可想而知的数肯定很大,所以需要开long long类型。

weixin_68643614的博客 239

UG二次开发之 三面摆正体代码分析

CIUGUIBlock 是一个从UIBlock 派生的一个类,为什么要从UIBlock 派生出CIUGUIBlock,这是为了兼容低版的UG。如果我们不从的UIBlock 派生控件类对象指针,在UG 8.5以下的版本,会出现编译错误的问题。这是一个简单的入门功能,包括了不少的常用的UF函,下面我们将结合成品代码一起分析一下常用的函数,这对初学者是必要的。根据创建好的UI控件,在 initialize_cb 中创建控件的指针对象。//根据选定的面,指定 X,Y坐标系轴。//根据变换的矩阵,平移实体。

u014657217的博客 351

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

线段树 lazy tag 小合集

(这里的基础和进阶纯粹是根据PO主水平说的…大家意思意思看看就好Orz)基础 poj 3468 hiho 1078 poj 2777 hdu 4902 进阶 hdu 3911 hdu 3397 未完待续基础poj 3468题目链接题意: 两种操作: 1. 对一段区间中的每一个数都加上一个值 2. 询问区间和我学习 lazy tag 的第一道题,可以说是十分经典的模板题了,看了dalao的博客然

kkkkahlua的博客 527

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Pascal 线段树 lazy-tag 模板

 先说下我的代码风格(很丑,勿喷) maxn表示最大空间的四倍 tree数组表示求和的线段树 delta表示增减的增量标记 sign表示覆盖的标记 delta,sign实际上都是lazy标志 pushdown表示标记下传 pushup表示标记上传(即求和,区间最值) update表示数据更新 ...

aocufei7257的博客 250

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

线段树Lazy Tag原理与实现:从区间加法到复杂场景应用

在算法与数据结构中,线段树是一种用于高效处理区间查询与更新的树形数据结构。其核心原理是通过二分思想将区间信息存储在树节点中,实现O(log N)时间复杂度的区间操作。然而,当面临区间批量更新时,传统线段树需要遍历底层所有叶子节点,效率会退化为O(N)。Lazy Tag(延迟标记)技术应运而生,它通过“打欠条”的方式,将更新操作延迟到真正需要时才执行,从而在保持对数时间复杂度的前提下,大幅提升了区间更新的效率。这一技术广泛应用于需要高效处理区间操作的场景,如动态区间求和、区间最值维护、区间赋值等。本文以**区

weixin_33725515的博客 578

POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】

Hotel Time Limit:3000MS Memory Limit:65536K 链接:POJ 3667 Description The cows are journeying north to ThunderBay in Canada to gain cultural...

adr5970的博客 124

线段树区间更新模板——懒标记(lazy-tag)的运用

前言 在线段树中会遇到区间更新的情况,例如 在区间求和问题中,令[a,b]区间内的值全部加c,若此时再采用单点更新的方法,就会耗费大量时间,这个时候就要用到懒标记来进行区间更新了。 懒标记(lazy-tag),又叫做延迟标记,举例说明。 设 当前结点对应区间[l, r],待更新区间[a, b]  当 a ≤ l ≤ r ≤ b,即 [l, r]∈[a,b]时,不再向下更新,仅更新当前结...

Plus Ultra! 1867

线段树成段更新操作及Lazy思想(POJ3468解题报告)

就直接那POJ上面的例题来说吧,http://poj.org/problem?id=3468。 此题题意很好懂:  给你N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c。 需要用到线段树的,update:成段增减,query:区间求和 介绍Lazy思想:lazy-tag思想,记录每一个线段树节点的变化值,当这部分线段的一致

fmt.Println( 1万+

浅析线段树(使用lazy tag)

这是百度百科上的图,线段树定义可以看这里-&amp;amp;amp;gt;定义戳我 任何一个区间都能被分成两个小区间,从而能够把对于大区间的查询转换为对几个小区间和小小区间和小小小区间……的查询。 这是我对线段树的朴素理解。 从图上也可以明显地看出任意一个长度大于1的区间都由两个小的子区间组成,子区间再往下分,直到区间内只有一个元素无法再分。**因此,对于每一个长度大于1的区间[l,r],有mid=(l+r...

hkr04的博客 2901

线段树Lazy-tag

由来线段树求区间极值的时候,每次都需要修改包含在插入区间的所有节点,这样是不可能承受的!于是lazy思想也就是Lazy-tag是一个非常不错的优化。实现lazy思想的含义就是“要做的时候再做,不然不做”。这听起来不太可能,但实际上根据树的性质,这是可以实现的,只需要使用Lazy-tag: 对于一个节点,我们记录一个tag表示还没有传递下去的值(也就是操作时到这个节点停止了,后面没有遍历过),然后

ZigZagK的博客 1451

线段树—Lazy_Tag

转载LINK:LAZY_TAG 先看一个具体问题吧 PKU 3468 http://poj.org/problem?id=3468 题意很清楚 1 ≤N,Q≤ 100000. "Cabc" means addingcto each ofAa,Aa+1, ... ,Ab. -10000 ≤c≤ 10000."Qab" means querying the sum ...

weixin_30781775的博客 117
上一篇: poj2528 Mayor's posters(线段树,离散化)
下一篇: hdu4578(三个更新操作,三个求值操作)
JinbaoSite0144
博客等级 码龄12年 231粉丝 157原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值