P3373 【模板】线段树 2

题目描述

如题,已知一个数列,你需要进行下面两种操作:

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的结果。

输入输出样例

输入样例#1:

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
输出样例#1:

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)

 
乘法的优先级永远比加法高。
代码如下:
 // LUOGU 3373 【模板】线段树2
// 2017.7.20 20:52
#include<bits/stdc++.h>
#define INF 0x3fffffff
#define MAXN 100000
#define MAXT MAXN*4
using namespace std;
typedef long long ll;
int N,M,topt=;
ll P,a[MAXN+];
struct sgt_node{
int lc,rc;
ll sum,pls,mul;
sgt_node(){pls=,mul=INF;}
}sgt[MAXT+];
int getint(){
char ch='*';
while(!isdigit(ch=getchar()));
int num=ch-'';
while(isdigit(ch=getchar()))num=num*+ch-'';
return num;
}
ll getll(){
char ch='*';
while(!isdigit(ch=getchar()));
ll num=ch-'';
while(isdigit(ch=getchar()))num=num*+ch-'';
return num;
}
#define lch sgt[now].lc
#define rch sgt[now].rc
#define smid ((l+r)>>1)
void update(int now){
sgt[now].sum=(sgt[lch].sum+sgt[rch].sum)%P;
}
void set_mul(int now,ll v){
sgt[now].sum=(sgt[now].sum*v)%P;
if(sgt[now].mul==INF)sgt[now].mul=v%P;
else sgt[now].mul=(sgt[now].mul*v)%P; // 必须为乘法!!!
sgt[now].pls=(sgt[now].pls*v)%P;
}
void set_pls(int now,int l,int r,ll v){
sgt[now].sum=(sgt[now].sum+v*(r-l+))%P;
sgt[now].pls=(sgt[now].pls+v)%P;
}
void push_down(int now,int l,int r){
if(sgt[now].mul!=INF){
set_mul(lch,sgt[now].mul);
set_mul(rch,sgt[now].mul);
sgt[now].mul=INF;
}
if(sgt[now].pls){
set_pls(lch,l,smid,sgt[now].pls);
set_pls(rch,smid+,r,sgt[now].pls);
sgt[now].pls=;
}
}
void Build_sgt(int &now,int l,int r){
now=++topt;
if(l==r){
sgt[now].sum=a[l];
return;
}
Build_sgt(lch,l,smid);
Build_sgt(rch,smid+,r);
update(now);
}
ll Query_sgt(int now,int l,int r,int qx,int qy){
if(l==qx&&r==qy)return sgt[now].sum;
push_down(now,l,r);
if(qy<=smid)return Query_sgt(lch,l,smid,qx,qy);
if(qx>smid)return Query_sgt(rch,smid+,r,qx,qy);
return Query_sgt(lch,l,smid,qx,smid)+Query_sgt(rch,smid+,r,smid+,qy);
}
void Region_mul(int now,int l,int r,int x,int y,ll v){
if(l==x&&r==y){
set_mul(now,v);
return;
}
push_down(now,l,r);
if(y<=smid)Region_mul(lch,l,smid,x,y,v);
else if(x>smid)Region_mul(rch,smid+,r,x,y,v);
else{
Region_mul(lch,l,smid,x,smid,v);
Region_mul(rch,smid+,r,smid+,y,v);
}
update(now);
}
void Region_pls(int now,int l,int r,int x,int y,ll v){
if(l==x&&r==y){
set_pls(now,l,r,v);
return;
}
push_down(now,l,r);
if(y<=smid)Region_pls(lch,l,smid,x,y,v);
else if(x>smid)Region_pls(rch,smid+,r,x,y,v);
else{
Region_pls(lch,l,smid,x,smid,v);
Region_pls(rch,smid+,r,smid+,y,v);
}
update(now);
}
int main(){
N=getint(),M=getint(),P=getll();
for(int i=;i<=N;i++)
a[i]=getll();
int root=;
Build_sgt(root,,N);
int op,x,y;
ll k;
for(int i=;i<=M;i++){
op=getint();
switch(op){
case :
x=getint(),y=getint(),k=getll();
Region_mul(,,N,x,y,k);
break;
case :
x=getint(),y=getint(),k=getll();
Region_pls(,,N,x,y,k);
break;
case :
x=getint(),y=getint();
printf("%lld\n",Query_sgt(,,N,x,y)%P);
break;
}
}
return ;
}

【原创】洛谷 LUOGU P3373 【模板】线段树2的更多相关文章

  1. 【洛谷 p3372】模板-线段树 1(数据结构--线段树)

    题目:已知一个数列,你需要进行下面两种操作:1.将某区间每一个数加上x:2.求出某区间每一个数的和. 解法:如题,模版题.需要加上 lazy 标记,也就是我的 upd.lazy 标记的思路就是对一个结 ...

  2. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  3. 洛谷p3384【模板】树链剖分题解

    洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...

  4. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

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

  5. 洛谷P3834 可持久化线段树(主席树)模板

    题目:https://www.luogu.org/problemnew/show/P3834 无法忍受了,我要写主席树! 解决区间第 k 大查询问题,可以用主席树,像前缀和一样建立 n 棵前缀区间的权 ...

  6. 洛谷 P3384 【模板】树链剖分

    树链剖分 将一棵树的每个节点到它所有子节点中子树和(所包含的点的个数)最大的那个子节点的这条边标记为"重边". 将其他的边标记为"轻边". 若果一个非根节点的子 ...

  7. 洛谷题解P4314CPU监控--线段树

    题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...

  8. 【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)

    Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...

  9. 『题解』洛谷P3384 【模板】树链剖分

    Problem Portal Portal1: Luogu Description 如题,已知一棵包含\(N\)个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作\(1\): ...

随机推荐

  1. C标准库常用函数概要

    stdio.h printf()/fprintf() printf的返回值是打印的字符数, 发生错误则返回负数 scanf()/fscanf() scanf的返回值是成功赋值的变量个数, 失败则返回E ...

  2. redis常用api

    一.全局命令 1.keys *            //查看所有键 2.dbsize           //键总数,如果存在大量键,线上禁止使用此命令 3.exists key     //存在返 ...

  3. 深入浅出GNU X86-64 汇编

    深入浅出GNU X86-64 汇编 来源 https://blog.csdn.net/pro_technician/article/details/78173777 原文 https://www3.n ...

  4. Django中 auto_now_add 和 auto_now 的区别

    auto_now_add = True #创建时添加的时间 修改数据时,不会发生改变 auto_now = True #修改数据的时间,每次修改都会有变动 ........

  5. VisualSVN Server 安装

    1.去官网下载:https://www.visualsvn.com/server/download/ 2.安装: 修改为后:  3.开机自动启动.

  6. docker 第五篇 存储

    镜像概述复习 Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层 如果运行中的容器修改了现有的一个已经存在的文件,那改文件将会从读写层下面的只读 ...

  7. c# 如何把一个同步方法变成异步方法

    1 例如有同步方法如下: private static void GenerateFile(DataTable dt) { } 2 变为异步方法 private static void Generat ...

  8. xss part2

    0x01 xss challenge level 6-10 1.1 level 6 test with typical, notice the script has changed change sc ...

  9. Spring Cloud(十一)高可用的分布式配置中心 Spring Cloud Bus 消息总线集成(RabbitMQ)

    详见:https://www.w3cschool.cn/spring_cloud/spring_cloud-jl8a2ixp.html 上一篇文章,留了一个悬念,Config Client 实现配置的 ...

  10. day01_人类社会货币的演变

    1.货币的自然演变 1.1:从实物货币(贝壳.金银等一般等价物的稀有性等价于被交换物品的价值)---纸质货币(国家信用背书,使得一文不值的纸币可以兑换价值百元的商品)---记账货币(微信.二维码.银行 ...