Luogu 3373 - 【模板】线段树 2 - [加乘线段树]
题目链接:https://www.luogu.org/problemnew/show/P3373
题目描述
如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
输入格式:
第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果
输出格式:
输出包含若干行整数,即为所有操作3的结果。
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
17
2
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^)
样例说明:

故输出应为17、2(40 mod 38=2)
题解:
由原本的单个的lazy标记变成两个标记:add标记和mul标记,一个记录加,一个记录乘;
需要注意的是,如果同时存在 $add$ 标记和 $mul$ 标记,应当先更新乘法标记,再更新加法标记,也就是说先把 $mul$ 标记pushdown,再把 $add$ 标记pushdown。
同时,由上面pushdown的顺序的缘故可知,当一个节点要乘以 $x$ 时,如果它的 $add$ 标记还存在,记得要把 $add$ 标记也乘 $x$(具体见代码的Update_Mul成员函数)。
(当然,如果你非头铁想要先把 $add$ 标记pushdown,再把 $mul$ 标记pushdown。那么,根据pushdown的顺序,当一个节点要加上 $x$ 时,如果它的 $mul$ 标记还存在,则要把 $x$ 除以 $mul$ 再加到 $add$ 标记上,不过在本题这样一个情况下估计是没法做了……)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=+; ll MOD;
int n,m;
ll a[maxn]; /********************************* Segment Tree - st *********************************/
struct Node
{
int l,r;
ll val;
ll add,mul;
void Update_Mul(ll x)
{
val=(val*x)%MOD;
mul=(mul*x)%MOD;
add=(add*x)%MOD;
}
void Update_Add(ll x)
{
val=(val+(r-l+)*x)%MOD;
add=(add+x)%MOD;
}
}node[*maxn];
void Pushdown(int root)
{
int ls=root*, rs=root*+;
if(node[root].mul!=)
{
node[ls].Update_Mul(node[root].mul);
node[rs].Update_Mul(node[root].mul);
node[root].mul=;
}
if(node[root].add)
{
node[ls].Update_Add(node[root].add);
node[rs].Update_Add(node[root].add);
node[root].add=;
}
}
void Pushup(int root)
{
node[root].val=(node[root*].val+node[root*+].val)%MOD;
}
void Build(int root,int l,int r) //对区间[l,r]建树
{
if(l>r) return;
node[root].l=l; node[root].r=r;
node[root].val=;
node[root].add=;
node[root].mul=;
if(l==r) node[root].val=a[l];
else
{
int mid=l+(r-l)/;
Build(root*,l,mid);
Build(root*+,mid+,r);
Pushup(root);
}
}
void Add(int root,int st,int ed,ll val) //区间[st,ed]全部加上val
{
if(st>node[root].r || ed<node[root].l) return;
if(st<=node[root].l && node[root].r<=ed) node[root].Update_Add(val);
else
{
Pushdown(root);
Add(root*,st,ed,val);
Add(root*+,st,ed,val);
Pushup(root);
}
}
void Mul(int root,int st,int ed,ll val) //区间[st,ed]全部加上val
{
if(st>node[root].r || ed<node[root].l) return;
if(st<=node[root].l && node[root].r<=ed) node[root].Update_Mul(val);
else
{
Pushdown(root);
Mul(root*,st,ed,val);
Mul(root*+,st,ed,val);
Pushup(root);
}
}
ll Query(int root,int st,int ed) //查询区间[st,ed]的和
{
if(st>node[root].r || ed<node[root].l) return ;
if(st<=node[root].l && node[root].r<=ed) return node[root].val;
else
{
Pushdown(root);
ll ls=Query(root*,st,ed);
ll rs=Query(root*+,st,ed);
Pushup(root);
return (ls+rs)%MOD;
}
}
/********************************* Segment Tree - st *********************************/ int main()
{
cin>>n>>m>>MOD;
for(int i=;i<=n;i++) scanf("%lld",&a[i]);
Build(,,n); for(int i=;i<=m;i++)
{
int op; scanf("%d",&op);
if(op==)
{
int x,y; ll k;
scanf("%d%d%lld",&x,&y,&k);
Mul(,x,y,k);
}
if(op==)
{
int x,y; ll k;
scanf("%d%d%lld",&x,&y,&k);
Add(,x,y,k);
}
if(op==)
{
int l,r; scanf("%d%d",&l,&r);
printf("%lld\n",Query(,l,r));
}
}
}
Luogu 3373 - 【模板】线段树 2 - [加乘线段树]的更多相关文章
- luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)
luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...
- Luogu 3373 又乘又加的线段树
Luogu 3373 又乘又加的线段树 当给一个节点加上一个加法标记时,直接把加法标记 += 新值: 当给一个节点加上一个乘法标记时,把乘法标记和加法标记同时 *= 新值.(注意pushdown函数中 ...
- 【Luogu P3371&P4779】【模板】单源最短路径(线段树优化Dijkstra)
线段树优化$\rm dijkstra$ 线段树每个节点维护$[l,r]$中$dist$最小的点,删除则把该点$dist$赋值为$+\infty$,然后更新该点影响到的线段树上的其他节点即可. 可以得到 ...
- Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)
Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- 洛谷P3380 【模板】二逼平衡树(树套树,树状数组,线段树)
洛谷题目传送门 emm...题目名写了个平衡树,但是这道题的理论复杂度最优解应该还是树状数组套值域线段树吧. 就像dynamic ranking那样(蒟蒻的Sol,放一个link骗访问量233) 所有 ...
- 【CF52C】Circular RMQ(线段树区间加减,区间最值)
给定一个循环数组a0, a1, a2, …, an-1,现在对他们有两个操作: Inc(le, ri, v):表示区间[le, ri]范围的数值增加v Rmq(le, ri):表示询问区间[le, r ...
- hdu 5111 树链剖分加函数式线段树
这题说的是给了两棵树,各有100000 个节点,然后Q个操作Q<=50000; 每个操作L1 R1 L2 R2.因为对于每棵树都有一个与本棵树其他点与众不同的值, 最后问 在树上从L1到R1这条 ...
- luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
LINK:字符串树 先说比较简单的正解.由于我没有从最简单的考虑答案的角度思考 所以... 下次还需要把所有角度都考察到. 求x~y的答案 考虑 求x~根+y~根-2*lca~根的答案. 那么问题变成 ...
随机推荐
- iOS中js与objective-c的交互(转)
因为在iOS中没有WebKit.Framework这个库的,所以也就没有 windowScriptObject对象方法了.要是有这个的方法的话 就方便多了,(ps:MacOS中有貌似) 现在我们利用其 ...
- WCF服务支持HTTP(get,post)方式请求例子
https://www.cnblogs.com/li150dan/p/9529413.html /// <summary> /// Http Get请求 /// </summary& ...
- MySql 错误 Err [Imp] 1153 - Got a packet bigger than 'max_allowed_packet' bytes
今天在用Navicat导入SQL文件时报错:MySql 错误 Err [Imp] 1153 - Got a packet bigger than 'max_allowed_packet' bytes ...
- 有人在贴吧问phpmyadmin如何设置插入的时候默认插入1条记录
在新版phpmyadmin中(我的版本是3.5.1) 插入的时候会提示插入两条,能够方便操作,让你多录入几条数据,如图 然而有人不想要这个界面默认插入两条,如何改为1条或者其他呢? 我审查了这个元素标 ...
- Weblogic(CVE-2017-10271)漏洞复现
WebLogic XMLDecoder反序列化漏洞(CVE-2017-10271) 漏洞编号:CVE-2017-10271 漏洞描述:WebLogic WLS组件中存在CVE-2017-10271远程 ...
- FFmpeg X264的preset和tune
鉴于x264的参数众多,各种参数的配合复杂,为了使用者方便,x264建议如无特别需要可使用preset和tune设置.这套开发者推荐的参数较为合理,可在此基础上在调整一些具体参数以符合自己需要,手动设 ...
- Android分包原理
如果App引用的库太多,方法数超过65536后无法编译.这是因为单个dex里面不能有超过65536个方法.为什么有最大的限制呢,因为Android会把每一个类的方法id检索起来,存在一个链表结构里面. ...
- make clean、make mrproper、make distclean的区别【转】
本文转载自:http://blog.csdn.net/liyayao/article/details/6818061 内核编译时, 到底用make clean, make mrproper还是make ...
- 新唐的开发环境的搭建,驱动以及BSP
https://www.keil.com/demo/eval/arm.htm#DOWNLOAD1,MDK-ARM的IDE集成开发环境:mdk512.exehttp://www.keil.com/fid ...
- Oralce分析函数
1 列传行 listagg(city,',') within GROUP (order by city) over (partition by nation) rank with temp ...