[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 老师交给小可可一个维护数列的任务,现在小可 ...
随机推荐
- 【HNOI2008】玩具装箱TOY & 斜率优化学习笔记
题目 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为 \(1\cdots N\ ...
- js解决img标签加载失败显示默认图片
问题: 为所有显示楼盘的页面添加一个加载失败的默认图片. 基本思路: img标签中有个onerror属性,专门用来处理加载失败的事件.所以可以用jquery添加onerror属性,在onerror中加 ...
- 07-Mysql数据库----数据类型
介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 详细参考链接:http://www.runoob.com/mysql/mysql-data- ...
- deeplearning.ai课程学习(4)
第四周:深层神经网络(Deep Neural Networks) 1.深层神经网络(Deep L-layer neural network) 在打算使用深层神经网络之前,先去尝试逻辑回归,尝试一层然后 ...
- android4.1 Wifi 浅析
简单分析下wifi相关类,首先了解几个主要概念 AsyncChannel 简单理解: AsyncChannel,就是借助Messenger 机制,让两个不同的handler之间进行通信. AsyncC ...
- c#程序中的AssemblyInfo.cs
在asp.net中有一个配置文件AssemblyInfo.cs主要用来设定生成的有关程序集的常规信息dll文件的一些参数,下面是默认的AssemblyInfo.cs文件的内容具体介绍 //是否符合公共 ...
- systemPath
<dependency> <groupId>com.aliyun.mns</groupId> <artifactId>aliyun-sdk-mn ...
- 简述jq中attr()和prop()的区别
attr,prop都是属性的意思,那他们有什么区别呢?我们先来看一下jquery的部分源码: attr部分: attr: function( elem, name, value, pass ) { v ...
- 纯Div+Css制作的漂亮点击按钮和关闭按钮
纯Div+Css制作的漂亮点击按钮和关闭按钮,单击点击按钮也有效果.这些都不是图片.
- 国内各运营商(ISP)IP段表
国内各运营商(ISP)IP段表 来源:http://bbs.hh010.com/forum.php?mod=viewthread&tid=490529&orderby=dateline ...