传送

感谢洛谷题解让我理清了这一撮标记

这里多了一个乘法操作,乘法的优先级高于加法。我们来思考一下有关标记的问题。

首先由两种操作,可以想到要有两个标记,一个标记乘法(mul[k]),一个标记加法(add[k])。

如果这一步是加法,就直接在原来的add上面增加即可(加法不会对mul产生影响)(这里的“原来的add”是指已经处理好加法,乘法关系的add),sum也按照线段树1的方式维护。

如果这一步是乘法,因为乘法的优先级高于加法,所以乘法会对当前的add产生影响,即add[k]要乘当前的数。mul[k],sum[k]直接乘当前的数即可。

再考虑一下标记下传。

子节点收到父亲节点的add和mul之后,我们就要考虑是先用父亲的add还是mul去更新子节点(即先乘再加还是先加再乘)。我们上面处理add的时候,就已经考虑到了mul对add的影响,如果这时候先加再乘,就会造成翻倍的错误,所以我们先乘再加(也就是先让子节点的add乘父节点的mul,再加上父节点的add)。sum[子节点]要先乘mul[父节点],再加上add[父节点]*(r-l+1)。

理清了两种标记之间的关系,剩下的就是线段树板子了。这里要注意建树的时候,mul[k]初始值为1,add[k]初始值为0。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=;
ll n,m,p;
ll val[N*],sum[N*],add[N*],mul[N*];
ll read()
{
char ch=getchar();
ll x=;bool f=;
while(ch<''||ch>'')
{
if(ch=='-')f=;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
if(f)x=-x;
return x;
}
void build(ll k,ll l,ll r)
{
mul[k]=;
if(l==r)
{
sum[k]=val[r];
return ;
}
ll mid=(l+r)>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
sum[k]=(sum[k<<]+sum[k<<|]+p)%p;
return;
}
void change(ll k,ll l,ll r,ll u)
{
add[k]=(mul[u]*add[k]%p+add[u])%p;//记得随时%p
mul[k]=(mul[k]*mul[u])%p;
sum[k]=(sum[k]*mul[u]%p+add[u]*(r-l+)%p)%p;
}
void pushdown(ll k,ll l,ll r)//标记下传
{
ll mid=(l+r)>>;
change(k<<,l,mid,k);
change(k<<|,mid+,r,k);
add[k]=;
mul[k]=;
return;
}
void Mul(ll k,ll l,ll r,ll x,ll y,ll 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 ;
}
pushdown(k,l,r);
ll mid=(l+r)>>;
if(x<=mid)
Mul(k<<,l,mid,x,y,v);
if(mid<y)
Mul(k<<|,mid+,r,x,y,v);
sum[k]=(sum[k<<]+sum[k<<|]+p)%p;
return;
}
void Add(ll k,ll l,ll r,ll x,ll y,ll v)
{
if(l>=x&&r<=y)
{
add[k]=add[k]+v;
sum[k]=(sum[k]+v*(r-l+)%p)%p;
return ;
} pushdown(k,l,r);
ll mid=(l+r)>>;
if(x<=mid)
Add(k<<,l,mid,x,y,v);
if(mid<y)
Add(k<<|,mid+,r,x,y,v);
sum[k]=(sum[k<<]+sum[k<<|]+p)%p;
return ;
}
ll query(ll k,ll l,ll r,ll x,ll y)
{
if(l>=x&&r<=y)
return sum[k]%p;
pushdown(k,l,r);
ll mid=(l+r)>>;
ll ans=;
if(x<=mid)
ans+=query(k<<,l,mid,x,y);
if(mid<y)
ans+=query(k<<|,mid+,r,x,y);
return (ans+p)%p; //防止出现负数
}
int main()
{
n=read();m=read();p=read();
for(int i=;i<=n;i++)
val[i]=read()%p;
build(,,n);
for(int i=;i<=N*;i++)
mul[i]=;
for(int i=;i<=m;i++)
{
ll cz,x,y;
cz=read();x=read();y=read();
if(cz==)
{
ll k=read();
Mul(,,n,x,y,k);
}
if(cz==)
{
ll k=read();
Add(,,n,x,y,k);
}
if(cz==)
{
printf("%lld\n",query(,,n,x,y));
}
}
}

线段树2(P3373)的更多相关文章

  1. [线段树]Luogu P3373 【模板】线段树 2

    #include<cstdio> #include<cstring> #include<algorithm> #define R register #define ...

  2. 洛谷P3373 【模板】线段树 2

     P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交  讨论  题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行 ...

  3. 洛谷 P3373 【模板】线段树 2 解题报告

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上\(x\) 2.将某区间每一个数加上\(x\) 3.求出某区间每一个数的和 输入输出格式 ...

  4. 洛谷P3373线段树模板2

    题目:https://www.luogu.org/problemnew/show/P3373 带乘的线段树,更新时把加的标记也乘一下,然后取值时先乘后加. 代码如下: #include<iost ...

  5. AC日记——【模板】线段树 2 洛谷 P3373

    P3373 [模板]线段树 2387通过1.8K提交标签难度 提高+/省选- 提交 讨论 题解 最新讨论 更多讨论 2333最后三个点卡常数.迷之RE感觉这题很迷啊好像一共三组测试数据.友情提示:开l ...

  6. 洛谷——P3373 【模板】线段树 2&& B 数据结构

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 线段树维护区间乘法 1.如何 ...

  7. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

  8. 洛谷 P3373 【模板】线段树 2 题解

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式 第一行包含三个整数 ...

  9. 【原创】洛谷 LUOGU P3373 【模板】线段树2

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第 ...

  10. P3373 【模板】线段树 2 (未完待续)

    P3373 [模板]线段树 2 强烈安利这个大佬 超赞!!! 题解 本来以为这个题拿着线段树1的板子改改就好了,但是发现事情并没有那么简单,改了两天... 我们看到这个题其实涉及啦乘法和加法两种运算, ...

随机推荐

  1. 20190903 On Java8 第十七章 文件

    第十七章 文件 在Java7中对 文件的操作 引入了巨大的改进.这些新元素被放在 java.nio.file 包下面,过去人们通常把nio中的n理解为new即新的io,现在更应该当成是non-bloc ...

  2. SQL的“增删改”

    结构语言分类 DDL(数据定义语言)  create  drop  alter   创建删除以及修改数据库,表,存储过程,触发器,索引.... DML(数据操作语言)   insert  delete ...

  3. Spark-Core RDD概述

    一.什么是RDD 1.RDD(Resilient Distributed DataSet)弹性分布式数据集 2.是Spark中最基本的数据抽象 3.在代码中是一个抽象类,它代表一个弹性的.不可变的.可 ...

  4. poj1305 Fermat vs. Pythagoras(勾股数)

    题目传送门 题意: 设不定方程:x^2+y^2=z^2若正整数三元组(x,y,z)满足上述方程,则称为毕达哥拉斯三元组.若gcd(x,y,z)=1,则称为本原的毕达哥拉斯三元组. 定理:正整数x,y, ...

  5. Sublime text设置快捷键让编写的HTML文件在打指定浏览器预览

    作者:浪人链接:https://www.zhihu.com/question/27219231/answer/43608776来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出 ...

  6. 身为一个小白,看到一篇值得看的文章。讲述小白学习python的6个方法。

    01. Python怎么学?   Python虽然号称非常简单,功能强大!但是再简单,它也是一门编程语言,任何一个编程语言都会包含: 内功,心法和招式,内功心法就是指的算法,数据结构: 招式就是任何一 ...

  7. java 中的引用类型

    GC基本原理 GC (Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征 ...

  8. docker安装es

    下载镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:6.8.1 创建容器并映射docker run -e ES_JAVA_OP ...

  9. Java 静态方法、私有方法、常量的使用

    1.静态方法 2.私有方法 3.常量 4.接口小结

  10. uboot学习之五-----uboot如何启动Linux内核

    uboot和内核到底是什么?uboot实质就是一个复杂的裸机程序:uboot可以被配置也可以做移植: 操作系统内核本身就是一个裸机程序,和我们学的uboot和其他裸机程序没有本质的区别:区别就是我们操 ...