[bzoj1798][Ahoi2009]Seq——线段树+多重标记下传
题意
请你写一个数据结构,支持:
- 子序列同加
- 子序列同乘
- 统计子序列和
题目
线段树裸题,但对于我这种初学者还是非常难写。
我们维护两个标记,一个是在这个节点上作过的所有乘法操作,一个是加法操作,始终保持乘法优先级在前,这就说明,如果原来已经有了加法,那么我们需要把加法让位,即把加法×乘法,然后乘法搞一下原来的值。
对于如果一个操作与一个区间不完全覆盖,我们需要把lazy标记下传,对于下传操作,也需要按照上面的方法计算优先级,同时更新节点sum值。
注意在加法操作时,不要使用节点的add值更新sum,而要用val,因为add已经计算在sum里面了。
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, p;
ll m;
const int maxn = 100005;
struct seg {
int l, r;
ll sum, add, tag;
} t[4 * maxn];
void build(int k, int l, int r) {
t[k].l = l;
t[k].r = r;
if (r == l) {
t[k].tag = 1;
t[k].add = 0;
scanf("%lld", &t[k].sum);
t[k].sum %= p;
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
t[k].sum = (t[k << 1].sum + t[k << 1 | 1].sum) % p;
t[k].add = 0;
t[k].tag = 1;
}
void pushdown(int k) {
if (t[k].add == 0 && t[k].tag == 1)
return;
ll ad = t[k].add, tag = t[k].tag;
ad %= p, tag %= p;
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
t[k << 1].tag = (t[k << 1].tag * tag) % p;
t[k << 1].add = ((t[k << 1].add * tag) % p + ad) % p;
t[k << 1].sum = (((t[k << 1].sum * tag) % p + (ad * (mid - l + 1) % p)%p)%p) % p;
t[k << 1 | 1].tag = (t[k << 1 | 1].tag * tag) % p;
t[k << 1 | 1].add = ((t[k << 1 | 1].add * tag) % p + ad) % p;
t[k << 1 | 1].sum = (((t[k << 1|1].sum * tag) % p + (ad * (r-mid) % p)%p)%p) % p;
t[k].add = 0;
t[k].tag = 1;
return;
}
void update(int k) { t[k].sum = (t[k << 1].sum%p + t[k << 1 | 1].sum%p) % p; }
void add(int k, int x, int y, ll val) {
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (x <= l && r <= y) {
t[k].add = (t[k].add + val) % p;
t[k].sum = (t[k].sum + (val * (r - l + 1) % p) % p) % p;
return;
}
pushdown(k);
if (x <= mid)
add(k << 1, x, y, val);
if (y > mid)
add(k << 1 | 1, x, y, val);
update(k);
}
void mul(int k, int x, int y, ll val) {
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (x <= l && r <= y) {
t[k].add = (t[k].add * val) % p;
t[k].tag = (t[k].tag * val) % p;
t[k].sum = (t[k].sum * val) % p;
return;
}
pushdown(k);
if (x <= mid)
mul(k << 1, x, y, val);
if (y > mid)
mul(k << 1 | 1, x, y, val);
update(k);
}
ll query(int k, int x, int y) {
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (x <= l && r <= y) {
return t[k].sum%p;
}
pushdown(k);
ll ans = 0;
if (x <= mid)
ans = (ans + query(k << 1, x, y)) % p;
if (y > mid)
ans = (ans + query(k << 1 | 1, x, y)) % p;
update(k);
return ans%p;
}
int main() {
// freopen("seq.in", "r", stdin);
// freopen("seq.ans", "w", stdout);
scanf("%lld %lld", &n, &p);
build(1, 1, n);
scanf("%d", &m);
while (m--) {
int q;
scanf("%d", &q);
if (q == 1) {
int x, y;
ll z;
scanf("%d%d%lld", &x, &y, &z);
z%=p;
mul(1, x, y, z);
} else if (q == 2) {
int x, y;
ll z;
scanf("%d%d%lld", &x, &y, &z);
z%=p;
add(1, x, y, z);
} else {
int x, y;
scanf("%d %d", &x, &y);
printf("%lld\n", query(1, x, y));
}
}
return 0;
}
[bzoj1798][Ahoi2009]Seq——线段树+多重标记下传的更多相关文章
- 【BZOJ】1798: [Ahoi2009]Seq 维护序列seq 线段树多标记(区间加+区间乘)
[题意]给定序列,支持区间加和区间乘,查询区间和取模.n<=10^5. [算法]线段树 [题解]线段树多重标记要考虑标记与标记之间的相互影响. 对于sum*b+a,+c直接加上即可. *c后就是 ...
- 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 (线段树 ,多重标记下放)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 7773 Solved: 2792[Submit ...
- 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树
题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...
- [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:$询 ...
- [BZOJ1798][AHOI2009]Seq维护序列 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798 一眼看过去线段树,事实上就是线段树.对于乘和加的两个标记,我们可以规定一个顺序,比如 ...
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )
线段树.. 打个 mul , add 的标记就好了.. 这个速度好像还挺快的...( 相比我其他代码 = = ) 好像是#35.. ---------------------------------- ...
- 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 老师交给小可可一个维护数列的任务,现在小可 ...
随机推荐
- windows 10 下的linux子系统用法 -- tmux分屏工具用法
1 激活linux子系统的方法见百度: 2 打开powershell,输入bash启动子系统终端:输入exit退出: 3 输入tmux attach连接会话:ctrl-b+d 返回终端:ctrl-b+ ...
- vs调试代码的时候断点无法命中
https://blog.csdn.net/xxdddail/article/details/18696399 该链接提供的解决方案主要是如下图片:禁用 图片标记的这个选项即可:
- .netcore centos环境搭建实战
步骤 1. 安装VMware Workstation 下载地址:https://my.vmware.com/cn/web/vmware/info/slug/desktop_end_user_compu ...
- 修改npm全局安装模式的路径
由于npm全局模块的存放路径及cache的路径默认是放在C盘下,这样肯定会增加C盘的负担,那么如果需要修改其存放路径应该怎么做呢? 第一步:在nodejs安装目录(也可以指定其它目录)下创建”node ...
- CPU拓扑结构
本篇旨在认识一下以下三种CPU拓扑结构分别是什么: Symmetric multiprocessing (SMP) Non-uniform memory access (NUMA) Simultane ...
- 九度OJ--Q1168
import java.util.Scanner; public class q1168 { public static void main(String[] args) { Scanner scan ...
- linux中升级安装python2.7
打算自建VPN,新购买了一个虚拟服务器,centOS6.6 自带的是python2.6,因为比较习惯python2.7,所以就升级到最新的python2.7.12 首先要安装:sudo yum ins ...
- OpenCV膨胀和腐蚀示例代码
#include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...
- JMS实战——ActiveMQ
安装 官网下载地址:http://activemq.apache.org/ 小编这里以5.9.0版本为例,做简单介绍. 下载之后解压到制定路径,目录结构如下: 启动 直接运行bin下的activemq ...
- 深夜浅谈我理解的DIV对SEO的影响
又到了夜深人静的时候,对于以前的我来说每天的这个时候都是在敲一下代码啊或者看一会书,但是今夜突然间又一次心血来潮,想写一篇博文来记录一下这一段时间做SEO优化所遇到的问题. 其实对于我来说SEO并不是 ...