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

说明

时空限制:1000ms,128M


好题。

我们分别维护两个\(lazytag\),分别表示乘法和加法优先

不妨规定乘法优先,加法滞后

意思就是当我们\(pushdown\)时,总是对原区间先进行乘法操作,再进行加法操作

这样对于加法修改,我们直接做不用管乘法

对于乘法操作,我们直接对加法和乘法的\(lazytag\)做同样的操作即可

对于询问我们都给\(pushdown\)掉


Code:

#include <cstdio>
#define ls id<<1
#define rs id<<1|1
#define ll long long
const int N=100010;
ll lazymul[N<<2],lazyadd[N<<2],sum[N<<2],a[N];
ll n,m,p;
void push_downadd(ll id,ll L,ll R)
{
if(L!=R)
{
ll mid=L+R>>1;
sum[ls]=(sum[ls]+(mid+1-L)*lazyadd[id])%p;
sum[rs]=(sum[rs]+(R-mid)*lazyadd[id])%p;
(lazyadd[ls]+=lazyadd[id])%=p;
(lazyadd[rs]+=lazyadd[id])%=p;
}
lazyadd[id]=0;
}
void push_downmul(ll id,ll L,ll R)
{
if(lazymul[id]==1) return;
if(L!=R)
{
ll mid=L+R>>1;
sum[ls]=(sum[ls]*lazymul[id])%p;
sum[rs]=(sum[rs]*lazymul[id])%p;
(lazymul[ls]*=lazymul[id])%=p;
(lazymul[rs]*=lazymul[id])%=p;
(lazyadd[ls]*=lazymul[id])%=p;
(lazyadd[rs]*=lazymul[id])%=p;
}
lazymul[id]=1;
}
void updata(ll id)
{
sum[id]=(sum[ls]+sum[rs])%p;
}
void changemul(ll id,ll l,ll r,ll L,ll R,ll mult)
{
push_downmul(id,L,R);
push_downadd(id,L,R);
if(l==L&&r==R)
{
sum[id]=(sum[id]*mult)%p;
lazymul[id]=(lazymul[id]*mult)%p;
return;
}
ll mid=L+R>>1;
if(r<=mid) changemul(ls,l,r,L,mid,mult);
else if(l>mid) changemul(rs,l,r,mid+1,R,mult);
else changemul(ls,l,mid,L,mid,mult),changemul(rs,mid+1,r,mid+1,R,mult);
updata(id);
}
void changeadd(ll id,ll l,ll r,ll L,ll R,ll delta)
{
push_downmul(id,L,R);
push_downadd(id,L,R);
if(l==L&&r==R)
{
sum[id]=(sum[id]+(R+1-L)*delta)%p;
lazyadd[id]=(lazyadd[id]+delta)%p;
return;
}
ll mid=L+R>>1;
if(r<=mid) changeadd(ls,l,r,L,mid,delta);
else if(l>mid) changeadd(rs,l,r,mid+1,R,delta);
else changeadd(ls,l,mid,L,mid,delta),changeadd(rs,mid+1,r,mid+1,R,delta);
updata(id);
}
ll query(ll id,ll l,ll r,ll L,ll R)
{
if(l==L&&r==R)
return sum[id];
push_downmul(id,L,R);
push_downadd(id,L,R);
ll mid=L+R>>1;
if(r<=mid) return query(ls,l,r,L,mid);
else if(l>mid) return query(rs,l,r,mid+1,R);
else return (query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R))%p;
}
void build(ll id,ll l,ll r)
{
lazymul[id]=1;
if(l==r)
{
sum[id]=a[l];
return;
}
ll mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
updata(id);
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&p);
ll opt,x,y,k;
for(int i=1;i<=n;i++)
scanf("%lld",a+i);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&opt,&x,&y);
if(opt==1)
{
scanf("%lld",&k);
changemul(1,x,y,1,n,k);
}
else if(opt==2)
{
scanf("%lld",&k);
changeadd(1,x,y,1,n,k);
}
else
printf("%lld\n",query(1,x,y,1,n));
}
return 0;
}

2018.7.25

洛谷 P3373 【模板】线段树 2 解题报告的更多相关文章

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

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

  2. 线段树_区间加乘(洛谷P3373模板)

    题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字 ...

  3. 洛谷 - P1198 - 最大数 - 线段树

    https://www.luogu.org/problemnew/show/P1198 要问区间最大值,肯定是要用线段树的,不能用树状数组.(因为没有逆元?但是题目求的是最后一段,可以改成类似前缀和啊 ...

  4. 洛谷 P2391 白雪皑皑 线段树+优化

    题目描述: 现在有 \(N\) 片雪花排成一列. Pty 要对雪花进行$ M $次染色操作,第 \(i\)次染色操作中,把\((i*p+q)%N+1\) 片雪花和第\((i*q+p)%N+1\)片雪花 ...

  5. 【洛谷】【线段树】P1471 方差

    [题目背景:] 滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西. [题目描述:] 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差 ...

  6. 【洛谷】【线段树】P1047 校门外的树

    [题目描述:] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L ...

  7. 【洛谷】【线段树】P1886 滑动窗口

    [题目描述:] 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. [输入格式:] 输入一共 ...

  8. 【洛谷】【线段树】P3353 在你窗外闪耀的星星

    [题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...

  9. 洛谷P5280 [ZJOI2019]线段树

      https://www.luogu.org/problemnew/show/P5280 省选的时候后一半时间开这题,想了接近两个小时的各种假做法,之后想的做法已经接近正解了,但是有一些细节问题理不 ...

随机推荐

  1. HTML基本代码教学,第三天

    HTML 今天由于个人情况,身体不适,但是为了大家的学习进度,咱们以纯文字得形式来简单了解下今天的学习内容 今儿咱们来了解下表单 <form id=" "  name=&qu ...

  2. NLP的12条精髓

    NLP是神经语言程序学 (Neuro-Linguistic Programming) 的英文缩写.一.没有两个人是一样的 No two persons are the same. 1.没有两个人的人生 ...

  3. Windows网络通信(二):socket异步编程

    简述 这里使用的API和同步编程的API是差不多的,只多了一个ioctlsocket和select函数.这里面涉及一个很重要的结构体fd_set.这里用到的API大部分都是windows和linux通 ...

  4. 网络基础知识-bps、Bps、pps的区别

    在计算机科学中,bit是表示信息的最小单位,叫做二进制位:一般用0和1表示.Byte叫做字节,由8个位(8bit)组成一个字节(1Byte),用于表示计算机中的一个字符.bit(比特)与Byte(字节 ...

  5. AngularJS学习之数据绑定

    既然AngularJS是以数据作为驱动的MVC框架,在上一篇文章中,也介绍了AngularJS如何实现MVC模式的,所有模型里面的数据,都必须经过控制器,才能展示到视图中. 什么是数据绑定 首先来回忆 ...

  6. scrum立会报告+燃尽图(第三周第五次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2286 项目地址:https://coding.net/u/wuyy694 ...

  7. Android开发随笔2

    昨天:对anroid的系统架构了解比如:基于linux内核,整合库函数和java编译器并且为上层提供封装好的api和一些基本系统级应用 创建一个安卓的模拟器 了解了ddms的作用和内容 利用已有的工具 ...

  8. 静默调用ShellContextMenu 实现QQ文件共享

    我在CSDN提问题一直没人回复,一下午时间自己终于解决了问题 http://bbs.csdn.net/topics/391916381 现将过程录下 先说需求,我想实现的功能是 在程序中对文件调用百度 ...

  9. 事后诸葛亮--Alpha版本总结

    目录 设想和目标 计划 资源 变更管理 设计/实现 测试/发布 团队的角色,管理,合作 总结: 本小组和其他组的评分 分工和贡献分 全组讨论的照片 问题 第一组提问回答:爸爸饿了队 第二组提问回答:拖 ...

  10. ubuntu关闭系统自动检测错误

    sudo gedit /etc/default/apport 将enabled=1 改成 enabled=0