【题解】洛谷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)把数列中的一 ...
随机推荐
- python2文件转换为exe可执行文件
windows下py文件的运行需要安装python,如果是exe文件就可以直接运行 1. 直接在命令行用pip安装 pyinstaller pip install pyinstaller 2 在命令行 ...
- Redis学习笔记1 -- 单机环境时分布式锁的使用
使用第三方开源组件Jedis实现Redis客户端,且只考虑Redis服务端单机部署的场景. 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKee ...
- SQL COUNT DISTINCT
Create table trade ( sell_id int, --卖家 buy_id int, -- 卖家 time date --交易时间 ) sell_id, buy_id, time s ...
- struts1 & jquery form 文件异步上传
1.概述 还在用struts1?是的,在地球的没写地方,落后的生产方式还在运转(老项目). 从 继承org.apache.struts.action.Action, 继承org.apache.stru ...
- linux 下解决git clone报错
解决报错:error: The requested URL returned error: 401 Unauthorized while accessing 问题报错:error: The req ...
- CSS性能优化新属性:will-change
---恢复内容开始--- will-change属性通过告诉浏览器什么属性.什么元素将会发生变化,可以对这些操作进行可能性的优化,由此提高CSS动画的执行效率. 这个属性可以有4个值: auto: 实 ...
- c++开发ocx入门实践二
原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/51374355 IDE:vs2010,c++,测试工具,vs自带的TstCo ...
- Mysql存储Emoji表情[为何utf8不能存储以及如何使Mysql能够存储Emoji表情]
https://segmentfault.com/a/1190000008533577
- Process.start: how to get the output?
1: Synchronous example static void runCommand() { Process process = new Process(); process.StartInfo ...
- 《C++ Primer Plus》读书笔记之二—复合类型
二.第四章 复合类型 1.C-风格字符串:C-风格字符串具有一种特殊的性质:以空字符结尾,空字符被写成\0,其ASC||编码为0,用来标记字符串的结尾.例如: char dog[5]={'b','e ...