【bzoj1798】[Ahoi2009]Seq 维护序列seq
大意:一个数组,三个操作,第一种是区间[a,b]每个数乘乘,第二种是区间[a,b]每个数加c,第三种是查询[a,b]区间的和并对p取摸。
两种操作就不能简单的只往下传标记。每次传乘法标记时,要把加法标记同时乘上乘法标记,例如某个区间先进来一个加法标记add,之后又进来一个乘法标记mul。
那么结果为(x+add)*mul=x*mul+add*mul。这样向下传标记的时候就相对独立。递归边界更新加法标记之前先乘上该节点的mul,左右儿子down的时候先将儿子的add乘上本节点的mul。
最后说一下sum,比如本节点的存在加法标记x和乘法标记y,并且是先加上x,再乘上y,则左儿子的sum要更新为(sum+x)*y。由于乘法标记传到本节点的时候更新了加法标记,x =x*y,所以sum[o<<1]=(左区间的长度*x)+sum[o<<1]*y。
- #include<algorithm>
- #include<iostream>
- #include<cstdlib>
- #include<cstring>
- #include<cstdio>
- #include<cmath>
- using namespace std;
- typedef long long LL;
- #define N 100010
- int n,m;
- int askd,al,ar,ask;
- LL p;
- LL add[N<<],sum[N<<],mul[N<<];
- void pushup(int now)
- {
- sum[now]=(sum[now<<]+sum[now<<|])%p;
- }
- void pushdown(int now,int d)
- {
- if (add[now]!= || mul[now]!=)
- {
- mul[now<<]=mul[now<<]*mul[now]%p;
- mul[now<<|]=mul[now<<|]*mul[now]%p;
- add[now<<]=(add[now]+add[now<<]*mul[now])%p;
- add[now<<|]=(add[now]+add[now<<|]*mul[now])%p;
- sum[now<<]=(add[now]*(d-(d>>))+sum[now<<]*mul[now])%p;
- sum[now<<|]=(add[now]*(d>>)+sum[now<<|]*mul[now])%p;
- add[now]=;
- mul[now]=;
- }
- }
- void build(int nowl,int nowr,int now)
- {
- sum[now]=;
- mul[now]=;
- if (nowl==nowr)
- {
- scanf("%lld",&sum[now]);
- return ;
- }
- int mid=(nowl+nowr)>>;
- build(nowl,mid,now<<);
- build(mid+,nowr,now<<|);
- pushup(now);
- }
- void updata_mul(int nowl,int nowr,int now,int l,int r,int c)
- {
- if (nowl>=l && nowr<=r)
- {
- add[now]=add[now]*c%p;
- sum[now]=sum[now]*c%p;
- mul[now]=mul[now]*c%p;
- return ;
- }
- pushdown(now,nowr-nowl+);
- int mid=(nowl+nowr)>>;
- if (l<=mid)
- updata_mul(nowl,mid,now<<,l,r,c);
- if (r>mid)
- updata_mul(mid+,nowr,now<<|,l,r,c);
- pushup(now);
- }
- void updata_add(int nowl,int nowr,int now,int l,int r,int c)
- {
- if (nowl>=l && nowr<=r)
- {
- add[now]=(add[now]+c)%p;
- sum[now]=(sum[now]+c*(nowr-nowl+))%p;
- return ;
- }
- pushdown(now,nowr-nowl+);
- int mid=(nowl+nowr)>>;
- if (l<=mid)
- updata_add(nowl,mid,now<<,l,r,c);
- if (r>mid)
- updata_add(mid+,nowr,now<<|,l,r,c);
- pushup(now);
- }
- LL query(int nowl,int nowr,int now,int l,int r)
- {
- LL res();
- if (nowl>=l && nowr<=r)
- return sum[now];
- pushdown(now,nowr-nowl+);
- int mid=(nowl+nowr)>>;
- if (l<=mid)
- res=(res+query(nowl,mid,now<<,l,r))%p;
- if (r>mid)
- res=(res+query(mid+,nowr,now<<|,l,r))%p;
- return res;
- }
- int main()
- {
- scanf("%d%lld",&n,&p);
- build(,n,);
- scanf("%d",&m);
- while (m--)
- {
- scanf("%d",&askd);
- if (askd==)
- {
- scanf("%d%d%d",&al,&ar,&ask);
- updata_mul(,n,,al,ar,ask);
- }
- if (askd==)
- {
- scanf("%d%d%d",&al,&ar,&ask);
- updata_add(,n,,al,ar,ask);
- }
- if (askd==)
- {
- scanf("%d%d",&al,&ar);
- printf("%lld\n",query(,n,,al,ar));
- }
- }
- return ;
- }
【bzoj1798】[Ahoi2009]Seq 维护序列seq的更多相关文章
- BZOJ1798: [Ahoi2009]Seq 维护序列seq[线段树]
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 5504 Solved: 1937[Submit ...
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )
线段树.. 打个 mul , add 的标记就好了.. 这个速度好像还挺快的...( 相比我其他代码 = = ) 好像是#35.. ---------------------------------- ...
- 1798: [Ahoi2009]Seq 维护序列seq
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 2930 Solved: 1087[Submit ...
- bzoj 1798: [Ahoi2009]Seq 维护序列seq (线段树 ,多重标记下放)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 7773 Solved: 2792[Submit ...
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeO ...
- Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可 ...
- BZOJ1798[Ahoi2009]Seq 维护序列seq 题解
题目大意: 有长为N的数列,有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值. ...
- 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树
题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...
- 【分块】bzoj1798 [Ahoi2009]Seq 维护序列seq
分块,打标记,维护两个标记:乘的 和 加的. 每次 区间乘的时候,对 乘标记 和 加标记 都 乘上那个值. 每次 区间加的时候 对 加标记 加上那个值. (ax+b)*v=axv+bv.开 long ...
- [bzoj1798][Ahoi2009]Seq 维护序列seq ([洛谷P3373]【模板】线段树 2)
题目大意:有$n$个数,有$m$个操作,有三种: $1\;l\;r\;x:$把区间$[l,r]$内的数乘上$x$ $2\;l\;r\;x:$把区间$[l,r]$内的数加上$x$ $3\;l\;r:$询 ...
随机推荐
- ORACLE中DBMS_SQL的用法
ORACLE中DBMS_SQL的用法 对于一般的select操作,如果使用动态的sql语句则需要进行以下几个步骤: open cursor---> parse---> define ...
- 初识Typescript及vscode环境配置
什么是typescript?为什么要用它? typescript简称ts,是js语法的一个超级,由微软团队维护的 js特点(不足) 弱类型:js中的数据变量没有确定的类型,可以存储对象,可以存储数字, ...
- BZOJ2007 NOI2010 海拔 平面图转对偶图 最小割
题面太长啦,请诸位自行品尝—>海拔 分析: 这是我见过算法比较明显的最小割题目了,很明显对于某一条简单路径,海拔只会有一次变换. 而且我们要最终使变换海拔的边权值和最小. 我们发现变换海拔相当于 ...
- 排序算法,以php为代码示例
一.冒泡排序 <?php/** * Created by PhpStorm. * User: 郑楚周 * Date: 2018/9/28 * Time: 16:10 */ /**冒泡排序 * C ...
- win7 x64安装glpk
下载glpk,下载地址:http://ftp.gnu.org/gnu/glpk/
- 22Spring基于配置文件的方式配置AOP
直接看代码: package com.cn.spring.aop.impl; //加减乘除的接口类 public interface ArithmeticCalculator { int add(in ...
- C语言的移位操作符及位运算
C语言的移位操作符 位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算.位移位运算符分为左移和右移两种,均为双目运算符.第一运算对象是移位对象,第二个运算对象是所移的二进制位数. 位 ...
- POJ 2096 找bug 期望dp
题目大意: 一个人受雇于某公司要找出某个软件的bugs和subcomponents,这个软件一共有n个bugs和s个subcomponents,每次他都能同时随机发现1个bug和1个subcompon ...
- noip模拟赛 残
分析:这道题有点丧病啊......斐波那契数列本来增长就快,n <= 10^100又套2层,看到题目就让人绝望.不过这种题目还是有套路的.首先求斐波那契数列肯定要用到矩阵快速幂,外层的f可以通过 ...
- 洛谷P1710地铁涨价
题目背景 本题开O2优化,请注意常数 题目描述 博艾市除了有海底高铁连接中国大陆.台湾与日本,市区里也有很成熟的轨道交通系统.我们可以认为博艾地铁系统是一个无向连通图.博艾有N个地铁站,同时有M小段地 ...