洛谷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] 维护序列(线段树)的更多相关文章

  1. 洛谷 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 ...

  2. 洛谷P2023 [AHOI2009]维护序列(线段树区间更新,区间查询)

    洛谷P2023 [AHOI2009]维护序列 区间修改 当我们要修改一个区间时,要保证 \(ax+b\) 的形式,即先乘后加的形式.当将区间乘以一个数 \(k\) 时,原来的区间和为 \(ax+b\) ...

  3. 洛谷 P2023 [AHOI2009]维护序列 题解

    P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中 ...

  4. 洛谷 P2023 [AHOI2009]维护序列

    P2023 [AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中 ...

  5. [洛谷P2023] [AHOI2009]维护序列

    洛谷题目链接:[AHOI2009]维护序列 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列 ...

  6. [P2023][AHOI2009]维护序列(线段树)

    题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...

  7. 洛谷 2023 [AHOI2009]维护序列

    洛谷 2023 [AHOI2009]维护序列 洛谷原题传送门 这个题也是一道经典的线段树模版(其实洛谷的模版二改一下输入顺序就能AC),其中包括区间乘法修改.区间加法修改.区间查询三个操作. 线段树的 ...

  8. BZOJ1798[Ahoi2009]维护序列——线段树

    题目描述     老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成.    有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2 ...

  9. [AHOI2009]维护序列 (线段树)

    题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...

随机推荐

  1. Hadoop 完全分布式部署(三节点)

    用来测试,我在VMware下用Centos7搭起一个三节点的Hadoop完全分布式集群.其中NameNode和DataNode在同一台机器上,如果有条件建议大家把NameNode单独放在一台机器上,因 ...

  2. Binder or AIDL的最简单实践

    1.前言: 在Android开发中多进程的合理使用+进程间通信的IPC是一个比较难的点.特别是Android特有的Binder机制,非常复杂,对于应用层开发的初级开发工程师强求深入理解Binder机制 ...

  3. 【Immutable】拷贝与JSON.parse(JSON.stringify()),深度比较相等与underscore.isEqual(),性能比较

    样本:1MB的JSON文件,引入后生成500份的一个数组: 结果如下: 拷贝性能: JSON.parse(JSON.stringify()) 的方法:2523.55517578125ms immuta ...

  4. after() 和 remove() 实现替换

    <div class="replacedDiv">this is the replaced div</div> <script>         ...

  5. 用CSS隐藏页面元素的5种方法

    1.opacity设置一个元素的透明度只是从视觉上隐藏元素,对页面布局还是有影响,读屏软件会原样读出 2.visibility设置为hidden将隐藏我们的元素,对网页布局还是起作用,子元素也会被隐藏 ...

  6. Python基础-面向过程编程实现Linux下cat -rl ‘dir’ |grep ‘keywords’ 功能

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. ...

  7. 【Udacity】数据的差异性:值域、IQR、方差和标准差

    一.值域(Range) Range = Max - Min 受异常值(Outliers)影响 二.四分位差(IQR) 四分位距(interquartile range, IQR),又称四分差.是描述统 ...

  8. toasf的苦水

    http://blog.csdn.net/qq_25867141/article/details/52807705 优化 上面的几种方式我大致也都走了一遍,其实我觉得都没啥区别,看你喜欢用哪种吧.我其 ...

  9. AWS的load balance

    Route53实现了地理上的load balance; ELB实现了region内的load balance CloudFront实现了静态内容的全网加速 ZULh?*;&T(

  10. SQL Server ->> 时间函数: EOMONTH, DATEFROMPARTS, TIMEFROMPARTS, DATETIMEFROMPARTS, DATETIMEOFFSETFROMPARTS

    上面几个函数都是SQL Server 2012新增的时间函数. EOMONTH 返回传入时间的月结束日,返回数据类型为DATE SELECT EOMONTH(GETDATE()) 结果为 DATEFR ...