[关闭]
@cww97 2018-10-27T11:22:47.000000Z 字数 3602 阅读 926

梦美的线段树 题解

NOIP


题目链接点这

这题有点毒瘤啊,__int128才能过,建议食用洛谷ide

介于前面三篇的都比较玄学(代码都比较丑),打算自己写一发

自己写的线段树常数应该比其他几篇大一点,为了方便理解吧

首先数学期望

这一步应该比较好计算,同时相信大部分人都死在了这里比如我

然后想到这题不是线段树维护期望,而是维护区间平方和

对于一个节点

  1. struct node{
  2. int sum, tag; // 常规都区间和 & 标记
  3. int len; 也很好理解
  4. // 然后就有些奇怪都东西了
  5. int len_2, len_sum, con;
  6. };

con: contribution, 即为该节点对答案分子的贡献,

因为con比较难以一步计算出来,所以考虑一个比较容易想到(放屁)的区间平方和

更新时,

sum +=

包含上子节点的话就是,,也就是 con

对于难以统计的 这里变可以单独维护,这里便是Node结构体里奇怪的len_sum, len_2,注释里标注了include child nodes,都是包含其子节点的。

那么考虑这两个奇怪的东西,

又回到了len_2

所以这里代码里对应的:

这么一来,线段树部分就很清晰了,自认为自己的数学功底很差,所以推公式的时候慢慢推,让像我一样的弱智都能看得懂

本来想交一发 long long先来个90分的,然后发现,前90分也要__int128,这便是这题毒瘤的地方了。代码量到这里已经可以了,何必再爆long long,数据结构配高精有意思吗?有意思吗?有意思吗?据观察大家都用的__int128过的。

不过听郭黑康说最后一个点q是MOD的倍数(题目不是保证不是倍数的吗???),没遇到这个坑,也不知道是不是我写法的原因,int128之后CE了几发就过了

最后输出答案的时候,gcd,power啥的,就不说了,老生常谈了

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef __int128 LL;
  4. const int N = (1e5 + 7) << 2;
  5. const LL MOD = 998244353;
  6. LL sqr(LL x){return x*x;}
  7. LL gcd(LL x, LL y){
  8. if (y) while((x %= y) && (y %= x));
  9. return x + y;
  10. }
  11. LL power(LL a, LL x){
  12. LL ans = 1;
  13. for (; x; x >>= 1){
  14. if (x & 1) ans = (ans * a) % MOD;
  15. a = (a * a) % MOD;
  16. }
  17. return ans % MOD;
  18. }
  19. //------------head & math-------------
  20. int arr[N];
  21. struct SegTree{
  22. #define lc (rt << 1)
  23. #define rc (rt << 1 | 1)
  24. #define lson rt<<1, l, mid
  25. #define rson rt<<1|1, mid+1, r
  26. int n;
  27. // for one Node
  28. LL sum[N], len[N], tag[N];
  29. LL len_2[N], len_sum[N]; // include child nodes
  30. LL con[N]; // contribution, also include child nodes
  31. // commonly pushUp
  32. void pushUp(const LL &rt) {
  33. sum[rt] = sum[lc] + sum[rc];
  34. len_sum[rt] = len[rt]*sum[rt] + len_sum[lc] + len_sum[rc];
  35. con[rt] = sqr(sum[rt]) + con[lc] + con[rc];
  36. }
  37. void Tag(const LL &rt, const LL &l, const LL &r, const LL &v){
  38. sum[rt] += v * (r-l+1);
  39. tag[rt] += v;
  40. con[rt] += 2*v*len_sum[rt] + sqr(v)*len_2[rt];
  41. len_sum[rt] += v * len_2[rt];
  42. }
  43. void pushDown(const LL &rt, const LL &l, const LL &r){
  44. if (!tag[rt]) return;
  45. LL mid = (l+r) >> 1;
  46. Tag(lson, tag[rt]);
  47. Tag(rson, tag[rt]);
  48. tag[rt] = 0;
  49. }
  50. void build(const LL &rt, const LL &l, const LL &r) {
  51. if (l == r) {
  52. sum[rt] = len_sum[rt] = (LL)arr[l];
  53. len[rt] = len_2[rt] = 1;
  54. tag[rt] = 0;
  55. con[rt] = sqr(sum[rt]);
  56. return;
  57. }
  58. LL mid = (l + r) >> 1;
  59. build(lson);
  60. build(rson);
  61. len[rt] = len[lc] + len[rc];
  62. len_2[rt] = sqr(len[rt]) + len_2[lc] + len_2[rc];
  63. tag[rt] = 0;
  64. pushUp(rt);
  65. }
  66. void update(const LL &rt, const LL &l, const LL &r, const LL &L, const LL &R, const LL &v) {
  67. if (L <= l && r <= R) {
  68. Tag(rt, l, r, v);
  69. return;
  70. }
  71. LL mid = (l + r) >> 1;
  72. pushDown(rt, l, r);
  73. if (L <= mid) update(lson, L, R, v);
  74. if (mid < R) update(rson, L, R, v);
  75. pushUp(rt);
  76. }
  77. void query(){ // print ans;
  78. LL p = con[1], q = sum[1], gd = gcd(p, q);
  79. p /= gd, q /= gd;
  80. //printf("%d, %d: ", p, q);
  81. LL ans = ((p%MOD) * power(q, MOD-2)) % MOD;
  82. printf("%lld\n", ans);
  83. }
  84. void print(LL rt, LL l, LL r){ // prLL tree, debug
  85. printf("%d: [%d, %d], len = %d, len_2 = %d, sum = %d, len_sum = %d, tag = %d, con = %d\n",
  86. rt, l, r, len[rt], len_2[rt], sum[rt], len_sum[rt], tag[rt], con[rt]);
  87. if (l == r) return;
  88. LL mid = (l + r) >> 1;
  89. print(rt<<1, l, mid);
  90. print(rt<<1|1, mid+1, r);
  91. }
  92. } T;
  93. int main(){
  94. //freopen("in.txt", "r", stdin);
  95. int n, m;
  96. scanf("%d%d", &n, &m);
  97. for (LL i = 1; i <= n; i++){
  98. scanf("%d", &arr[i]);
  99. }
  100. T.build(1, 1, n);
  101. //T.print(1, 1, n);
  102. for (int op, l, r, v; m--;){
  103. scanf("%d", &op);
  104. if (op==2) T.query();
  105. else{ // update
  106. scanf("%d%d%d", &l, &r, &v);
  107. T.update(1, 1, n, l, r, v);
  108. }
  109. }
  110. return 0;
  111. }

最后再扯点啥呢,自己写结构体都是把结构体当成class来用的,就当是全是publicclass

define lson, rson也是一个令人愉悦的点,跟kuangbing学的

还有哪里看不懂欢迎私戳我提问或者cww970329@qq.com

附件:
- 可能炸的公式1 image.png-9.9kB
- 可能炸的公式1 image.png-22.4kB
- 可能炸的公式2 image.png-27.7kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注