线段树——懒标记下放
创始人
2024-06-03 17:26:38
0

【模板】线段树 1

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 kkk。
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n,mn, mn,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 nnn 个用空格分隔的整数,其中第 iii 个数字表示数列第 iii 项的初始值。

接下来 mmm 行每行包含 333 或 444 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 [x,y][x, y][x,y] 内每个数加上 kkk。
  2. 2 x y:输出区间 [x,y][x, y][x,y] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

样例 #1

样例输入 #1

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

样例输出 #1

11
8
20

提示

对于 30%30\%30% 的数据:n≤8n \le 8n≤8,m≤10m \le 10m≤10。
对于 70%70\%70% 的数据:n≤103n \le {10}^3n≤103,m≤104m \le {10}^4m≤104。
对于 100%100\%100% 的数据:1≤n,m≤1051 \le n, m \le {10}^51≤n,m≤105。

保证任意时刻数列中所有元素的绝对值之和 ≤1018\le {10}^{18}≤1018。

【样例解释】

懒标记用于计算每个线段的变化程度,在这题就是每个线段增加的数之和,当我们的add操作和query操作都没有遍历到所输入的x y的时候,我们就需要不断的把懒标记进行下放,下放完之后我们还得记得维护f的值,使其不失真,具体看代码

#include
#define ll long long
using namespace std;
ll f[400005],v[400005];
int n,m,a[100005];
inline void buildtree(int k,int l,int r){if(l==r){f[k]=a[l];return;}int mid=(l+r)>>1;buildtree(k<<1,l,mid);buildtree(k<<1|1,mid+1,r);f[k]=f[k<<1]+f[k<<1|1];
}
inline void push_down(int k){//将懒标记点下放v[k<<1]+=v[k],v[k<<1|1]+=v[k],v[k]=0;
}
inline void push_up(int k,int l,int r,int m){//维护f[k]的值,使其不失真f[k]=f[k<<1]+v[k<<1]*(m-l+1)+f[k<<1|1]+v[k<<1|1]*(r-m);
}
inline void add(int k,int l,int r,int x,int y,int num){if(l==x&&r==y){v[k]+=num;return;}if(v[k])push_down(k);int mid=(l+r)>>1;if(y<=mid)add(k<<1,l,mid,x,y,num);elseif(x>mid)add(k<<1|1,mid+1,r,x,y,num);else add(k<<1,l,mid,x,mid,num),add(k<<1|1,mid+1,r,mid+1,y,num);push_up(k,l,r,mid);
}
inline ll query(int k,int l,int r,int x,int y){if(l==x&&r==y)return f[k]+v[k]*(r-l+1);if(v[k])push_down(k);int mid=(l+r)>>1;ll res;if(y<=mid)res=query(k<<1,l,mid,x,y);elseif(x>mid)res=query(k<<1|1,mid+1,r,x,y);else res=query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y);push_up(k,l,r,mid);return res;
}
int main(){cin>>n>>m;for(int i=1;i<=n;++i)scanf("%d",&a[i]);buildtree(1,1,n);while(m--){int t,x,y,num;scanf("%d%d%d",&t,&x,&y);if(t==1){scanf("%d",&num);add(1,1,n,x,y,num);}else cout<

【模板】线段树 2

题目描述

如题,已知一个数列,你需要进行下面三种操作:

  • 将某区间每一个数乘上 xxx

  • 将某区间每一个数加上 xxx

  • 求出某区间每一个数的和

输入格式

第一行包含三个整数 n,m,pn,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 nnn 个用空格分隔的整数,其中第 iii 个数字表示数列第 iii 项的初始值。

接下来 mmm 行每行包含若干个整数,表示一个操作,具体如下:

操作 111: 格式:1 x y k 含义:将区间 [x,y][x,y][x,y] 内每个数乘上 kkk

操作 222: 格式:2 x y k 含义:将区间 [x,y][x,y][x,y] 内每个数加上 kkk

操作 333: 格式:3 x y 含义:输出区间 [x,y][x,y][x,y] 内每个数的和对 ppp 取模所得的结果

输出格式

输出包含若干行整数,即为所有操作 333 的结果。

样例 #1

样例输入 #1

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

样例输出 #1

17
2

提示

【数据范围】

对于 30%30\%30% 的数据:n≤8n \le 8n≤8,m≤10m \le 10m≤10
对于 70%70\%70% 的数据:$n \le 10^3 ,,, m \le 10^4$
对于 100%100\%100% 的数据:$ n \le 10^5,,, m \le 10^5$

除样例外,p=571373p = 571373p=571373

(数据已经过加强_

样例说明:

故输出应为 171717、222( 40mod38=240 \bmod 38 = 240mod38=2 )

对于这道题,我们首先能确认懒标记应该要有两个,因为对于add而言,懒标记的初始值应该为0,而对于mul而言,懒标记的初始值应该为1,两者肯定不可能是同一个懒标记。
但是对于懒标记mul,初始化起来比较复杂,因此最好的方式就是就是在建树的时候初始化为1,这时候构造结构体的必要性就有了。
下放需要有个规则,首先,下放的时候对于add而言,应该乘以父亲结点的mul,再加上父亲结点的add;对于mul而言,直接乘以父亲结点的mul即可;对于val而言,其等于自己原本的val父亲的mul再加上线段长度父亲的add,说起来有点绕,具体看代码即可

#include
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m,p,a[N];
struct node{ll val,add,mul;int len;
}t[4*N];
inline void buildtree(int k,int l,int r){t[k].add=0,t[k].mul=1;t[k].len=(r-l+1);if(l==r){t[k].val=a[l];return;}int mid=(l+r)>>1;buildtree(k<<1,l,mid),buildtree(k<<1|1,mid+1,r);t[k].val=(t[k<<1].val+t[k<<1|1].val)%p;
}
inline void push_down(int k){t[k<<1].add=(t[k<<1].add*t[k].mul+t[k].add)%p;t[k<<1].mul=(t[k<<1].mul*t[k].mul)%p;t[k<<1].val=t[k<<1].val*t[k].mul%p+t[k<<1].len*t[k].add%p;t[k<<1|1].add=(t[k<<1|1].add*t[k].mul+t[k].add)%p;t[k<<1|1].mul=t[k<<1|1].mul*t[k].mul%p;t[k<<1|1].val=t[k<<1|1].val*t[k].mul%p+t[k<<1|1].len*t[k].add%p;t[k].mul=1,t[k].add=0;
}
inline void push_up(int k){t[k].val=(t[k<<1].val+t[k<<1|1].val)%p;
}
inline void modify(int k,int l,int r,int x,int y,int add,int mul){if(l==x&&y==r){t[k].val=(t[k].val*mul%p+t[k].len*add)%p;t[k].mul=t[k].mul*mul%p;t[k].add=(t[k].add*mul%p+add)%p;return;}if(t[k].add!=0||t[k].mul!=1)push_down(k);int mid=(l+r)>>1;if(y<=mid)modify(k<<1,l,mid,x,y,add,mul);elseif(x>mid)modify(k<<1|1,mid+1,r,x,y,add,mul);else modify(k<<1,l,mid,x,mid,add,mul),modify(k<<1|1,mid+1,r,mid+1,y,add,mul);push_up(k);
}
inline ll query(int k,int l,int r,int x,int y){if(l==x&&r==y)return t[k].val;if(t[k].add!=0||t[k].mul!=1)push_down(k);int mid=(l+r)>>1;ll res;if(y<=mid)res=query(k<<1,l,mid,x,y);elseif(x>mid)res=query(k<<1|1,mid+1,r,x,y);else res=(query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y))%p;return res;
}
int main(){cin>>n>>m>>p;for(int i=1;i<=n;++i)scanf("%d",&a[i]);buildtree(1,1,n);while(m--){int c,x,y,k;scanf("%d%d%d",&c,&x,&y);if(c==1){scanf("%d",&k);modify(1,1,n,x,y,0,k);}else if(c==2){scanf("%d",&k);modify(1,1,n,x,y,k,1);}else printf("%lld\n",query(1,1,n,x,y));}
}

上一篇:K8S---Helm

下一篇:Django web开发(一) - 前端

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
JAVA多线程知识整理 Java多线程基础 线程的创建和启动 继承Thread类来创建并启动 自定义Thread类的子类&#...
【洛谷 P1090】[NOIP... [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G ...
国民技术LPUART介绍 低功耗通用异步接收器(LPUART) 简介 低功耗通用异步收发器...
城乡供水一体化平台-助力乡村振... 城乡供水一体化管理系统建设方案 城乡供水一体化管理系统是运用云计算、大数据等信息化手段࿰...
程序的循环结构和random库...   第三个参数就是步长     引入文件时记得指明字符格式,否则读入不了 ...
中国版ChatGPT在哪些方面... 目录 一、中国巨大的市场需求 二、中国企业加速创新 三、中国的人工智能发展 四、企业愿景的推进 五、...
报名开启 | 共赴一场 Flu... 2023 年 1 月 25 日,Flutter Forward 大会在肯尼亚首都内罗毕...
汇编00-MASM 和 Vis... Qt源码解析 索引 汇编逆向--- MASM 和 Visual Studio入门 前提知识ÿ...
【简陋Web应用3】实现人脸比... 文章目录🍉 前情提要🌷 效果演示🥝 实现过程1. u...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
windows安装JDK步骤 一、 下载JDK安装包 下载地址:https://www.oracle.com/jav...
分治法实现合并排序(归并排序)... 🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨...
在linux上安装配置node... 目录前言1,关于nodejs2,配置环境变量3,总结 前言...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
Linux内核进程管理并发同步... 并发同步并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理...
opencv学习-HOG LO... 目录1. HOG(Histogram of Oriented Gradients,方向梯度直方图)1...
EEG微状态的功能意义 导读大脑的瞬时全局功能状态反映在其电场结构上。聚类分析方法一致地提取了四种头表面脑电场结构ÿ...
【Unity 手写PBR】Bu... 写在前面 前期积累: GAMES101作业7提高-实现微表面模型你需要了解的知识 【技...