【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
洛谷P2023:https://www.luogu.org/problemnew/show/P2023
思路
需要2个Lazy-Tag
一个表示加的 一个表示乘的
需要先计算乘法 再计算加法
来自你谷milkfilling大佬的解释:
①加法优先,即规定好segtree[root*2].value=((segtree[root*2].value+segtree[root].add)*segtree[root].mul)%p,问题是这样的话非常不容易进行更新操作,假如改变一下add的数值,mul也要联动变成奇奇怪怪的分数小数损失精度,我们内心是很拒绝的;
②乘法优先,即规定好segtree[root*2].value=(segtree[root*2].value*segtree[root].mul+segtree[root].add*(本区间长度))%p,这样的话假如改变add的数值就只改变add,改变mul的时候把add也对应的乘一下就可以了,没有精度损失,看起来很不错。
所以这道题就是模板题啦~
易错点会在代码中详细注释出来
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 100007
#define ll long long
ll sum[maxn<<],add[maxn<<],mul[maxn<<],a[maxn],n,m,p;
void build(ll l,ll r,ll k)
{
mul[k]=;//初始化标记
if(l==r)
{
sum[k]=a[l]%p;
mul[k]=;
return;
}
ll mid=(l+r)>>;
build(l,mid,k<<);//左右子树构建
build(mid+,r,k<<|);
sum[k]=(sum[k<<]+sum[k<<|])%p;//维护sum值
}
void pushdown(ll l,ll r,ll mid,ll k)//标记下放
{
//先乘后加
if(mul[k]!=)//当有乘法标记 计算所有的值
{
sum[k<<]=(sum[k<<]*mul[k])%p;
sum[k<<|]=(sum[k<<|]*mul[k])%p;
mul[k<<]=(mul[k<<]*mul[k])%p;
mul[k<<|]=(mul[k<<|]*mul[k])%p;
add[k<<]=(add[k<<]*mul[k])%p;//加法标记也要乘
add[k<<|]=(add[k<<|]*mul[k])%p;
mul[k]=;//清除标记
}
if(add[k])//当有加法标记
{
sum[k<<]=(sum[k<<]+add[k]*(mid-l+)%p)%p;//左右子树计算 右子树不用+1
sum[k<<|]=(sum[k<<|]+add[k]*(r-mid)%p)%p;//注意这里要先算sum 再算add
add[k<<]=(add[k]+add[k<<])%p;//如果先算add 那再sum中的add值已经改变
add[k<<|]=(add[k]+add[k<<|])%p;//坑了我一个晚上(太弱了)
add[k]=;//清除标记
}
return;
}
void update1(ll x,ll y,ll v,ll l,ll r,ll k)//在定区间[x,y]加上v
{
if(l>=x&&r<=y)//如果整个区间包含
{
add[k]=(add[k]+v)%p;
sum[k]=(sum[k]+(r-l+)*v)%p;
return;
}
ll mid=(l+r)>>;
pushdown(l,r,mid,k);
if(x<=mid) update1(x,y,v,l,mid,k<<);
if(mid<y) update1(x,y,v,mid+,r,k<<|);
sum[k]=(sum[k<<]+sum[k<<|])%p;//计算标记下放之后的值
return;
}
void update2(ll x,ll y,ll v,ll l,ll r,ll k)//在定区间[x,y]乘上v
{
if(l>=x&&r<=y)//如果整个区间包含
{
mul[k]=(mul[k]*v)%p;
add[k]=(add[k]*v)%p;
sum[k]=(sum[k]*v)%p;
return;
}
ll mid=(l+r)>>;
pushdown(l,r,mid,k);
if(x<=mid) update2(x,y,v,l,mid,k<<);
if(mid<y) update2(x,y,v,mid+,r,k<<|);
sum[k]=(sum[k<<]+sum[k<<|])%p;//计算标记下放之后的值
return;
}
ll query(ll x,ll y,ll l,ll r,ll k)
{
if(l>=x&&r<=y) return sum[k]%p;
ll mid=(l+r)>>;
ll res=;
pushdown(l,r,mid,k);//标记下放
if(x<=mid) res+=query(x,y,l,mid,k<<);
res%=p;
if(y>mid) res+=query(x,y,mid+,r,k<<|);
return res%p;
}
int main()
{
cin>>n>>p;
for(ll i=;i<=n;i++) cin>>a[i];
cin>>m;
build(,n,);
for(ll i=;i<=m;i++)
{
ll x,y,z;
cin>>x;
if(x==)
{
cin>>x>>y>>z;
update2(x,y,z,,n,);
}
else if(x==)
{
cin>>x>>y>>z;
update1(x,y,z,,n,);
}
else if(x==)
{
cin>>x>>y;
cout<<query(x,y,,n,)<<endl;
}
}
}
【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)的更多相关文章
- 洛谷 P2023 [AHOI2009]维护序列 || 线段树加法和乘法运算
原理倒是非常简单.设原数为x,加法的lazytag为b,乘法的lazytag为a,操作数为c,那么原式为ax+b,乘上c后(ax+b)c=(ac)*x+b*c,加上c后(ax+b)+c=ax+(b+c ...
- 洛谷P2023 [AHOI2009]维护序列(线段树区间更新,区间查询)
洛谷P2023 [AHOI2009]维护序列 区间修改 当我们要修改一个区间时,要保证 \(ax+b\) 的形式,即先乘后加的形式.当将区间乘以一个数 \(k\) 时,原来的区间和为 \(ax+b\) ...
- 洛谷 P2023 [AHOI2009]维护序列 题解
P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中 ...
- 洛谷 P2023 [AHOI2009]维护序列
P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中 ...
- [洛谷P2023] [AHOI2009]维护序列
洛谷题目链接:[AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列 ...
- [P2023][AHOI2009]维护序列(线段树)
题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...
- 洛谷 2023 [AHOI2009]维护序列
洛谷 2023 [AHOI2009]维护序列 洛谷原题传送门 这个题也是一道经典的线段树模版(其实洛谷的模版二改一下输入顺序就能AC),其中包括区间乘法修改.区间加法修改.区间查询三个操作. 线段树的 ...
- BZOJ1798[Ahoi2009]维护序列——线段树
题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2 ...
- [AHOI2009]维护序列 (线段树)
题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...
随机推荐
- Spring课程 Spring入门篇 7-1 Aspect介绍及PointCut注解应用
本节主要是理论型: 关键看下节实操. 这个其实只要理解一点:使用AspectJ进行Spring AOP 编程,其实就是使用了JAVA注解的风格进行配置和使用. 不像之前讲的那样在配置文件中配置使用.
- java TreeSet 实现存自定义不可重复数据
本文主要是介绍一下java集合中的比较重要的Set接口下的可实现类TreeSet TreeSet类,底层用二叉树的数据结构 * 集合中以有序的方式插入和抽取元素. * 添加到TreeSet中的元素必须 ...
- SPOJ QTREE7
题意 一棵树,每个点初始有个点权和颜色 \(0 \ u\) :询问所有\(u,v\) 路径上的最大点权,要满足\(u,v\) 路径上所有点的颜色都相同 $1 u \(:反转\)u$ 的颜色 \(2 ...
- Python入门-初始面向对象
之前我们代码基本上都是面向过程的,今天我们就来初始一下python中一个重要的内容:面向对象 一.面向对象和面向过程(重点理解) 1.面向过程: 一切以事物的流程为核心. 核心是"过程&qu ...
- js-TextArea的换行符处理
js-txt文本处理 写自己主页项目时所产生的小问题拿出来给大家分享分享,以此共勉. ---DanlV TextArea的换行符处理 TextArea文本转换为Html:写入数据库时使用 js获取了t ...
- 鼠标事件-拖拽(不能拖出窗口的div)
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- RocketMQ读书笔记3——消费者
[不同类型的消费者] DefaultMQPushConsumer 由系统控制读取操作,收到消息后自动调用传入的处理方法来处理. DefaultMQPullConsumer 读取操作中的大部分功能由使用 ...
- arcgis 线段合并
对于上面这种这种有一个字段相同的 线段,使用 使用后生成的矢量如下
- Java—maven项目管理
Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建.报告和文档的软件项目管理工具. Maven环境搭建 http://maven.apache.org/download.c ...
- mongodb数据库集合操作
1:更新update update() 方法用于更新已存在的文档.语法格式如下: db.collection.update( <query>, <update>, { upse ...