线段树多个信息的传递(加法和乘法) seq
来源:互联网 发布:如何检测网络是否稳定 编辑:程序博客网 时间:2024/05/10 05:44
用线段树对一段的数据进行单纯的加法、乘法,这些都不难,只需要在某个区间内做个懒标记,然后经过每个结点时都把懒标记往下传递。
如果有多个标记,最简单的就是加减混合。多个信息的难点就在于如何把信息结合起来,要知道5 + (6 * 2)是不等于(5 + 6) * 2的。
这题需要把懒标记写成d * x + y,原数据是d,先乘上x再加y(x的缺省值是1,y是0)。
如果有一个操作要加上p,那么就有:
-> (d * x + y) + p
-> d * x + (y + p)
-> d * x + y' (y' = y + p)
如果有一个操作要乘以q,那么就有:
-> (d * x + y) * q
-> d * x * q + y * q
-> d * x' + y' (x' = x * q, y' = y * q)
这样就能把信息结合起来了。
当然,你也可以用(d + x) * y的形式,可以算一下,是可以的,问题就在于有除法,这个不仅运算慢,而且精度不高。
下面是代码(1是乘法,2是加法,3是询问):
#include <cstdio>#include <iostream>using namespace std;#define N 100007#define NODE 262147long long P, sum[NODE], dem[NODE], dep[NODE];void build(int root, int lo, int hi) { if (lo == hi) scanf("%I64d", &sum[root]); else { int mi = (lo + hi) >> 1, L = root << 1, R = L | 1;; build(L, lo, mi); build(R, mi + 1, hi); sum[root] = (sum[L] + sum[R]) % P; dem[root] = 1LL; }}void down(int root, int lo, int hi) { int mi = (lo + hi) >> 1, L = root << 1, R = L | 1; dem[L] = (dem[L] * dem[root]) % P; dem[R] = (dem[R] * dem[root]) % P; dep[L] = (dep[L] * dem[root] + dep[root]) % P; dep[R] = (dep[R] * dem[root] + dep[root]) % P; sum[L] = (sum[L] * dem[root] + dep[root] * (mi - lo + 1)) % P; sum[R] = (sum[R] * dem[root] + dep[root] * (hi - mi)) % P; dem[root] = 1LL; dep[root] = 0LL;}void modify(int root, int lo, int hi, int x, int y, long long c, bool t) { if (y < lo || x > hi) return; if (x <= lo && y >= hi) if (t) { dem[root] = (dem[root] * c) % P; dep[root] = (dep[root] * c) % P; sum[root] = (sum[root] * c) % P; } else { dep[root] = (dep[root] + c) % P; sum[root] = (sum[root] + c * (hi - lo + 1)) % P; } else { int mi = (lo + hi) >> 1, L = root << 1, R = L | 1; down(root, lo, hi); modify(L, lo, mi, x, y, c, t); modify(R, mi + 1, hi, x, y, c, t); sum[root] = (sum[L] + sum[R]) % P; }}long long ask(int root, int lo, int hi, int x, int y) { if (y < lo || x > hi) return 0; if (x <= lo && y >= hi) return sum[root]; int mi = (lo + hi) >> 1, L = root << 1, R = L | 1; down(root, lo, hi); return (ask(L, lo, mi, x, y) + ask(R, mi + 1, hi, x, y)) % P;}int main() { freopen("seq.in", "r", stdin); freopen("seq.out", "w", stdout); int n; scanf("%d%I64d\n", &n, &P); build(1, 0, n - 1); int m; scanf("\n%d", &m); while (m --) { int t, lo, hi, c; scanf("\n%d%d%d", &t, &lo, &hi); lo --, hi --; if (t < 3) { scanf("%d", &c); modify(1, 0, n - 1, lo, hi, (long long) c, t == 1); } else cout << ask(1, 0, n - 1, lo, hi) << endl; } return 0;}
- 线段树多个信息的传递(加法和乘法) seq
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)
- 线段树(加法和乘法的模板)
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和
- HYSBZ 1798(Ahoi2009) Seq 维护序列seq(区间更新+加法乘法混合操作)
- (1798: [Ahoi2009]Seq 维护序列seq)<线段树乘法操作>
- 分数的加法和乘法
- 多项式的加法和乘法
- 矩阵的加法和乘法
- 高精度(乘法和加法)
- 计算器的加法和乘法的实现
- 大数加法和大数乘法的实现
- python的矩阵加法和乘法
- c++一元多项式的乘法和加法
- js加法和乘法的精确计算
- 大数据的乘法和加法
- 大整数的加法、减法和乘法
- 一元多项式的加法和乘法运算
- Eclipse导入Android工程报错 Invalid project description
- 详解 ARM Linux启动过程分析
- SiteMesh介绍
- 类型转换
- 球和杯子
- 线段树多个信息的传递(加法和乘法) seq
- SolrPhpClient 支持solr4.x 的问题
- stuts1入门
- 十个iOS面试问题
- 递归方式求最大数
- hdu1873 看病要排队
- 最小移动数
- 数字的字符串处理
- UVA 11039 模拟