Link

UOJ LOJ Luogu

Solution

很玄妙的一道题,考察了对线段树较本质的理解 然而我并不会这个所谓最可做的题

首先,虽然题目很复杂,好像每个点的标记变化都很玄学,但是我们可以深入挖一挖性质。

假设我们现在的总区间为 \([1, 16]\),现在执行了修改 \(\text{M}\small\text{ODIFY}\)\([4, 10]\),那么线段树上的结点状况如下:

根据各个结点的性质我们将其分类。

  • Type 1:未标记,与询问区间半覆盖,这些结点上的标记会全部被 \(\text P\small\text{USHDOWN}\)。
  • Type 2:用红色标记,与询问区间全覆盖,恰好停止向下访问的结点,会在此处直接打标记走人。
  • Type 3:用绿色标记,与询问区间无交,但可以得到来自 Type 1 \(\text P\small\text{USHDOWN}\) 而来的标记。
  • Type 4:用橙色标记,与询问区间全覆盖,但无法被访问到。
  • Type 5:用蓝色标记,与询问区间无交,同时也得不到 \(\text P\small\text{USHDOWN}\) 而来的标记。

注意到性质相同的结点可以相同处理,这便是我们分类的意义所在。


接下来考虑一个 dp。我们必然不能把线段树真的拿去复制,于是直接在一个线段树上搞。

很容易想到的一个状态是,\(f_i(x)\) 表示在第 \(i\) 次 \(\text{M}\small\text{ODIFY}\) 之后,所有线段树中,位置 \(x\) 上有 tag 的线段树有几棵。

但是这样是不够的:Type 3 的转移需要视其线段树上祖先的 tag 情况而定。

于是再设 \(g_i(x)\) 为第 \(i\) 次 \(\text{M}\small\text{ODIFY}\) 之后,所有线段树中,\(x\to 1\) (祖先)的路径上不存在任何一个 tag 的线段树有几棵。

这样一来 Type 3 的问题自然解决了。

根据结点的 Type 进行分类讨论,设计转移:

  • Type 1:

    • 当前这个位置修改后必不可能存在标记,因为不管之前有没有都将被 \(\text P\small\text{USHDOWN}\)。
    • \(f_i(x) \leftarrow f_{i-1}(x)\)
    • \(g_i(x)\leftarrow g_{i-1}(x) + 2^{i-1}\)
  • Type 2:
    • 当前这个位置修改后必定存在标记,因为我们打 tag 打的就是这。
    • \(f_i(x)\leftarrow f_{i-1}(x) + 2^{i-1}\)
    • \(g_i(x)\leftarrow g_{i-1}(x)\)
  • Type 3:
    • 这里到底会不会有标记,还得看上头有没有东西可以传下来。
    • 其中共有 \(2^{i-1}-g_{i-1}(x)\) 棵线段树是存在至少一个标记的,只要有一个此处就得的到标记,这些会参与 \(f\) 的转移当中。
    • 至于 \(g\) 如何,原先有的还是有,没有的还是没有,该咋样咋样,复制一次刚好就 \(\times 2\)。
    • \(f_i(x)\leftarrow f_{i-1}(x)+2^{i-1}-g_{i-1}(x)\)
    • \(g_i(x)\leftarrow 2g_{i-1}(x)\)
  • Type 4:
    • 由于 Type 4 的点在 Type 2 的点之下,而 Type 2 必定有 tag,于是上头不可能没有 tag。
    • 这里不会被遍历到,标记状况不会变,该咋样咋样。
    • \(f_i(x)\leftarrow 2f_{i-1}(x)\)
    • \(g_i(x)\leftarrow g_{i-1}(x)\)
  • Type 5:
    • 被遗忘的角落,啥都不会变。
    • \(f_i(x)\leftarrow 2f_{i-1}(x)\)
    • \(g_i(x)\leftarrow 2g_{i-1}(x)\)

于是这题就做完了……吗?

我们发现,Type 1、2、3 的点数都不超过 \(O(\log n)\),这些暴力的话问题也不大,不过 Type 4、5 的点数可以达到难以接受的 \(O(n)\)。

但别忘了,现在我们是在线段树上搞 dp!线段树的标配是什么?懒标记!

既然题面上都这么多标记,那我们 Type 4、5 同样可以打标记,而且只需要维护一个乘法标记就行了。

然后差不多真的就做完了,细节还是挺多的。注意这里空间需要开大一倍,我们比一般线段树多往下更新了一层。

实现的话,只要在伪代码基础上改改就行。

Code

  1. /*
  2. * Author : _Wallace_
  3. * Source : https://www.cnblogs.com/-Wallace-/
  4. * Problem : ZJOI2019 线段树
  5. */
  6. #include <cstdio>
  7. using namespace std;
  8. const int N = 1e5 + 5;
  9. const int mod = 998244353;
  10. typedef long long LL;
  11. int n, m;
  12. LL f[N << 3], g[N << 3];
  13. LL tf[N << 3], tg[N << 3]; // multiplication tags
  14. LL sf[N << 3]; // sum of f in a subtree
  15. #define mid ((l + r) >> 1)
  16. #define dirL x << 1, l, mid
  17. #define dirR x << 1 | 1, mid + 1, r
  18. void pushup(int x) {
  19. sf[x] = (sf[x << 1] + sf[x << 1 | 1] + f[x]) % mod;
  20. }
  21. void build(int x, int l, int r) {
  22. f[x] = 0ll, g[x] = 1ll, tf[x] = tg[x] = 1ll, sf[x] = 0ll;
  23. if (l == r) return;
  24. build(dirL), build(dirR), pushup(x);
  25. }
  26. void update_f(int x, LL v) {
  27. (f[x] *= v) %= mod, (sf[x] *= v) %= mod, (tf[x] *= v) %= mod;
  28. }
  29. void update_g(int x, LL v) {
  30. (g[x] *= v) %= mod, (tg[x] *= v) %= mod;
  31. }
  32. void pushdown(int x) {
  33. if (tf[x] != 1ll) {
  34. update_f(x << 1, tf[x]);
  35. update_f(x << 1 | 1, tf[x]);
  36. tf[x] = 1ll;
  37. }
  38. if (tg[x] != 1ll) {
  39. update_g(x << 1, tg[x]);
  40. update_g(x << 1 | 1, tg[x]);
  41. tg[x] = 1ll;
  42. }
  43. }
  44. LL k = 1ll;
  45. void modify(int x, int l, int r, int ql, int qr) {
  46. pushdown(x);
  47. int lc = x << 1, rc = lc | 1;
  48. if (ql <= l && r <= qr) {
  49. (f[x] += k) %= mod; // type 2
  50. update_f(lc, 2), update_f(rc, 2); // type 4
  51. } else {
  52. (g[x] += k) %= mod; // type 1
  53. if (qr <= mid) {
  54. modify(dirL, ql, qr), pushdown(rc);
  55. (f[rc] += (k - g[rc] + mod) % mod) %= mod; // type 3
  56. (g[rc] *= 2) %= mod; // type 3
  57. update_f(rc << 1, 2), update_f(rc << 1 | 1, 2); // type 5
  58. update_g(rc << 1, 2), update_g(rc << 1 | 1, 2); // type 5
  59. pushup(rc);
  60. } else if (ql > mid) {
  61. modify(dirR, ql, qr), pushdown(lc);
  62. (f[lc] += (k - g[lc] + mod) % mod) %= mod; // type 3
  63. (g[lc] *= 2) %= mod; // type 3
  64. update_f(lc << 1, 2), update_f(lc << 1 | 1, 2); // type 5
  65. update_g(lc << 1, 2), update_g(lc << 1 | 1, 2); // type 5
  66. pushup(lc);
  67. } else {
  68. modify(dirL, ql, qr), modify(dirR, ql, qr);
  69. }
  70. }
  71. pushup(x);
  72. }
  73. #undef mid
  74. signed main() {
  75. scanf("%d%d", &n, &m);
  76. build(1, 1, n);
  77. for (int i = 1; i <= m; i++) {
  78. int opt, l, r;
  79. scanf("%d", &opt);
  80. if (opt == 1) {
  81. scanf("%d%d", &l, &r);
  82. modify(1, 1, n, l, r);
  83. (k *= 2) %= mod;
  84. }
  85. else printf("%d\n", sf[1]);
  86. }
  87. return 0;
  88. }

【ZJOI2019】线段树(线段树 & dp)的更多相关文章

  1. Codeforces Round #278 (Div. 1) Strip (线段树 二分 RMQ DP)

    Strip time limit per test 1 second memory limit per test 256 megabytes input standard input output s ...

  2. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  3. Codeforce 101B. Buses(线段树or树状数组+离散化)

     Buses                                                                                               ...

  4. HDU 5877 dfs+ 线段树(或+树状树组)

    1.HDU 5877  Weak Pair 2.总结:有多种做法,这里写了dfs+线段树(或+树状树组),还可用主席树或平衡树,但还不会这两个 3.思路:利用dfs遍历子节点,同时对于每个子节点au, ...

  5. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  6. BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3196 可以处理区间问题的平衡树. 3196: Tyvj 1730 二逼平衡树 Time Lim ...

  7. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  8. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

  9. 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

    如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...

  10. HDOJ 4417 - Super Mario 线段树or树状数组离线处理..

    题意: 同上 题解: 抓着这题作死的搞~~是因为今天练习赛的一道题.SPOJ KQUERY.直到我用最后一种树状数组通过了HDOJ这题后..交SPOJ的才没超时..看排名...时间能排到11名了..有 ...

随机推荐

  1. vscode remote wsl 的NoPermissions permission denied问题

    在 wsl这个目录  code-insiders . 之后会报这个错 无法打开"wsl": Unable to read file (NoPermissions (FileSyst ...

  2. C++的四种强制转型形式:

    C++同时提供了四种新的强制转型形式(通常称为新风格的或C++风格的强制转型): const_cast(expression)dynamic_cast(expression)reinterpret_c ...

  3. prop()和attr()我该翻谁的牌子?

    先上代码: // 全选 function CheckAll() { if ($("#th_checkbox").prop('checked')) $('input[name=&qu ...

  4. ceph luminous 新功能之内置dashboard

    前言 ceph luminous版本新增加了很多有意思的功能,这个也是一个长期支持版本,所以这些新功能的特性还是很值得期待的,从底层的存储改造,消息方式的改变,以及一些之前未实现的功能的完成,都让ce ...

  5. SQL Server 数据库bak备份文件还原操作和mdf文件附加操作

    前言:现在任何软件都离不开数据的支持,数据的价值是无价的,因此数据目前显得尤为重要,日常软件生产库的数据定时或实时备份必不可少,备份出的文件也需要进行验证,下边我将介绍SQL Server数据的的备份 ...

  6. 回溯算法 - n 皇后问题

    (1)问题描述 在 n × n 格的棋盘上放置彼此不受攻击的 n 个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n 后问题等价于在 n × n 的棋盘上放置 n 个 ...

  7. webpack 无法打包:No configuration file found and no output filename configured via CLI option

    报错内容 No configuration file found and no output filename configured via CLI option.A configuration fi ...

  8. pikachs 渗透测试2-XSS漏洞及利用

    一.概述 XSS(跨站脚本)概述 Cross-Site Scripting 简称为"CSS",为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS.一般XS ...

  9. 使用Camtasia创作抖音卡点视频

    空闲的时候刷一刷抖音相信已经成为很多人的日常啦,抖音里面的视频形式多种多样,而其中的卡点视频更是被大家热烈追捧.如果你外出旅行拍摄了很多好看的照片,就很适合用卡点视频的形式展现出来. 如果你想要制作这 ...

  10. 使用Camtasia给视频课件添加自动聚焦的效果

    随着现在抖音与微课市场的大火,原来可能只是因为兴趣爱好而剪辑制作了一些视频为爱发电,现在却完全可以当作一个事业来做了. 但是课件录制的时候,大部分的录制屏幕软件都是全屏或者固定屏幕大小录制的,有些小细 ...