博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈线段树中加与乘标记的下放
阅读量:6599 次
发布时间:2019-06-24

本文共 3510 字,大约阅读时间需要 11 分钟。

感觉题解里面对加和乘标记下放的顺序讲的不是很清楚,要么是直接没说,要么是一句话带过

如果想看1080P高清无码证明的可以报洛谷冬令营省选班,去看第一天的回放233

假设我们一个节点为\([val,mul,add]\),其中\(val\)代表该节点的权值,\(mul\)为乘法标记,\(add\)为加法标记

那么我们有两种表示方式,

  • 第一种:先加再乘

此时该节点为\((val+add)*mul\)

当再遇到一个\([\_mul,\_add]\)的标记时,

此时节点为\([(val+add)*mul+\_add]*\_mul\)

把式子展开并重新化为\((val+add')*mul'\)的形式

(也就是提出\(mul*\_mul\)这一项)得

\((val+add+\frac{\_add}{mul})*mul*\_mul\)

我们发现这里有个除法,会损失很多精度

因此我们换一个思路

  • 第二种:先乘再加

此时该节点为\((val*mul)+add\)

当再遇到一个\([\_mul,\_add]\)的标记时,

此时节点为\([(val*mul)+add]*\_mul+\_add\)

把式子展开并重新化为\((val*mul')+add'\)的形式

\(val*mul*\_mul+add*\_mul+\_add\)

我们发现这样不需要除法,因此我们选用第二种

其实线段树标记的下放一般都是这个套路

建议大家做完这道题后再去做一下

放一下丑陋的代码

#include
#include
#include
#define ls k<<1#define rs k<<1|1#define int long longusing namespace std;const int MAXN = 1e6 + 10;inline int read() { char c = getchar(); int x = 0, f = 1; while (c < '0' || c > '9') {if (c == '-')f = -1; c = getchar();} while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();} return x * f;}int N, M, mod;struct node { int mul, add, sum, l, r, siz;} T[MAXN];void update(int k) { T[k].sum = (T[ls].sum % mod + T[rs].sum % mod) % mod;}void ps(int x, int f) { T[x].mul = (T[x].mul % mod * T[f].mul % mod) % mod; T[x].add = (T[x].add * T[f].mul) % mod; T[x].add = (T[x].add + T[f].add) % mod; T[x].sum = (T[x].sum % mod * T[f].mul % mod) % mod; T[x].sum = (T[x].sum + T[f].add % mod * T[x].siz) % mod;}void pushdown(int k) { if (T[k].add == 0 && T[k].mul == 1) return ; ps(ls, k); ps(rs, k); T[k].add = 0; T[k].mul = 1;}void Build(int k, int ll, int rr) { T[k].l = ll; T[k].r = rr; T[k].siz = rr - ll + 1; T[k].mul = 1; if (ll == rr) { T[k].sum = read() % mod; return ; } int mid = ll + rr >> 1; Build(ls, ll, mid); Build(rs, mid + 1, rr); update(k);}void IntervalMul(int k, int ll, int rr, int val) { if (ll <= T[k].l && T[k].r <= rr) { T[k].sum = (T[k].sum * val) % mod; T[k].mul = (T[k].mul * val) % mod; T[k].add = (T[k].add * val) % mod; return ; } pushdown(k); int mid = T[k].l + T[k].r >> 1; if (ll <= mid) IntervalMul(ls, ll, rr, val); if (rr > mid) IntervalMul(rs, ll, rr, val); update(k);}void IntervalAdd(int k, int ll, int rr, int val) { if (ll <= T[k].l && T[k].r <= rr) { T[k].sum = (T[k].sum + T[k].siz * val) % mod; T[k].add = (T[k].add + val) % mod; return ; } pushdown(k); int mid = T[k].l + T[k].r >> 1; if (ll <= mid) IntervalAdd(ls, ll, rr, val); if (rr > mid) IntervalAdd(rs, ll, rr, val); update(k);}int IntervalSum(int k, int ll, int rr) { int ans = 0; if (ll <= T[k].l && T[k].r <= rr) { ans = (ans + T[k].sum) % mod; return ans; } pushdown(k); int mid = T[k].l + T[k].r >> 1; if (ll <= mid) ans = (ans + IntervalSum(ls, ll, rr)) % mod; if (rr > mid) ans = (ans + IntervalSum(rs, ll, rr)) % mod; return ans % mod;}main() {#ifdef WIN32 freopen("a.in", "r", stdin);#endif N = read(); M = read(); mod = read(); Build(1, 1, N); while (M--) { int opt = read(); if (opt == 1) { int l = read(), r = read(), val = read() % mod; IntervalMul(1, l, r, val); } else if (opt == 2) { int l = read(), r = read(), val = read() % mod; IntervalAdd(1, l, r, val); } else if (opt == 3) { int l = read(), r = read(); printf("%lld\n", IntervalSum(1, l, r) % mod); } } return 0;}

转载地址:http://bxlio.baihongyu.com/

你可能感兴趣的文章
MariaDB CEO 痛斥云厂商对开源的无尽掠夺,从不回馈社区
查看>>
修改yarn监控web页面上展示的StartFime和FinishTime【GMT时间】
查看>>
用Python完成Excel的常用操作
查看>>
Google在线深度学习神器Colab
查看>>
欧盟百万欧元悬赏开源软件漏洞惹争议,被评本末倒置
查看>>
微软职位内部推荐-Software Development Engineer
查看>>
慧安金科完成1亿元A轮融资,创新工场领投
查看>>
Auto Scaling控制台新变化:创建多可用区的伸缩组
查看>>
Spring Cloud的核心特性
查看>>
网站的伸缩性架构
查看>>
编程艺术是,而且一直以来都是 —— 语言设计艺术。
查看>>
python网络编程基础
查看>>
hadoop发行版本之间的区别
查看>>
阿里云安全算法大赛震撼启动 这次玩的是“实战”
查看>>
Kubernetes如何选择存储以及什么方式使用存储
查看>>
HyperLedger Fabric ChainCode开发——shim.ChaincodeStubInterface用法
查看>>
重构才是写代码,需求只是干活。
查看>>
基本数据结构和算法回顾
查看>>
【Java入门提高篇】Day28 Java容器类详解(十)LinkedHashMap详解
查看>>
避免把路走窄,程序员须记住:解决问题比写代码更重要
查看>>