牛客练习赛28 - B

传送门

题目

qn姐姐最好了~

​ qn姐姐给你了一个长度为n的序列还有m次操作让你玩,

​ 1 l r 询问区间[l,r]内的元素和

​ 2 l r 询问区间[l,r]内的

元素的平方

​ 3 l r x 将区间[l,r]内的每一个元素都乘上x

​ 4 l r x 将区间[l,r]内的每一个元素都加上x

输入描述:

  1. 第一行两个数n,m
  2. 接下来一行n个数表示初始序列
  3. 就下来m行每行第一个数为操作方法opt
  4. opt=1或者opt=2,则之后跟着两个数为l,r
  5. opt=3或者opt=4,则之后跟着三个数为l,r,x
  6. 操作意思为题目描述里说的

输出描述:

  1. 对于每一个操作1,2,输出一行表示答案

输入

复制

  1. 5 6
  2. 1 2 3 4 5
  3. 1 1 5
  4. 2 1 5
  5. 3 1 2 1
  6. 4 1 3 2
  7. 1 1 4
  8. 2 2 3

输出

复制

  1. 15
  2. 55
  3. 16
  4. 41

备注:

  1. 对于100%的数据 n=10000,m=200000 (注意是等于号)
  2. 保证所有询问的答案在long long 范围内

虽然这道题暴力能卡过去,真的是卡过去的,什么乱七八糟的宏定义、全局变量都要删了。。。


线段树做法:主要是处理x[i] * x[i]的前 n 项和,这里sum[][0]表示前区间和,sum[][1]表示区间内的元素平方和。

这里x = mul * x + add;下面是做各种操作后sum及懒惰标记的变化

乘法 * num:

mul[rt] = mul[rt] * num

add[rt] = add[rt] * num (如果add = 0,那么add * num = 0,如果add = a, 那么 x = (mul * x + a) * num,即 x = mul * num * x + a * num,按照x = mul * x + add的格式)

sum[][0] = sum[][0] * num

sum[][1] = sum[][1] * num * num

加法 + num:

add[rt] += num

sum[][1] += 2 * sum[][0] * num + (r - l + 1) * num * num

这里的sum[][0]是还没改变的,即这里先处理sum[][1],下面再处理sum[][0]。先来看单个元素的变化,(x + num) * (x + num) = x * x + 2 * num * x + num * num, 然后多个这样的式子相加,即可得上式,也可以解释为什么先处理sum[][1]

sum[][0] += (r - l + 1) * num

最后要记得long long,查询和更新都要下推标记,mul[]要初始化

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <string>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <queue>
  7. #include <iomanip>
  8. #include <stack>
  9. #include <algorithm>
  10. #include <vector>
  11. #include <functional>
  12. using namespace std;
  13. typedef long long LL;
  14. #define Fil(Array, len, num) fill(Array, Array + len, num)
  15. #define lson l, m, rt << 1
  16. #define rson m + 1, r, rt << 1 | 1
  17. const double PI = 3.1415926;
  18. const double E = 2.1718281828;
  19. const int MAXN = 10005;
  20. const int INF = 0x3f3f3f3f;
  21. const int MOD = 1e9 + 7;
  22. LL sum[MAXN << 2][3], add[MAXN << 2], mul[MAXN << 2];
  23. void PushUp(LL rt)
  24. {
  25. sum[rt][0] = sum[rt << 1][0] + sum[rt << 1 | 1][0];
  26. sum[rt][1] = sum[rt << 1][1] + sum[rt << 1 | 1][1];
  27. }
  28. void PushDown(LL ln, LL rn, LL rt)
  29. {
  30. if(mul[rt] != 1)
  31. {
  32. mul[rt << 1] *= mul[rt], mul[rt << 1 | 1] *= mul[rt];
  33. sum[rt << 1][1] *= mul[rt] * mul[rt], sum[rt << 1 | 1][1] *= mul[rt] * mul[rt];
  34. sum[rt][0] *= mul[rt], sum[rt << 1 | 1][0] *= mul[rt];
  35. mul[rt] = 1;
  36. }
  37. if(add[rt])
  38. {
  39. add[rt << 1] += add[rt], add[rt << 1 | 1] += add[rt];
  40. sum[rt << 1][1] += 2 * sum[rt << 1][0] * add[rt] + ln * add[rt] * add[rt];
  41. sum[rt << 1 | 1][1] += 2 * sum[rt << 1 | 1][0] * add[rt] + rn * add[rt] * add[rt];
  42. sum[rt << 1][0] += ln * add[rt], sum[rt << 1 | 1][0] += rn * add[rt];
  43. add[rt] = 0;
  44. }
  45. }
  46. void Build(LL l, LL r, LL rt)
  47. {
  48. add[rt] = 0, mul[rt] = 1;
  49. if(l == r)
  50. {
  51. scanf("%lld", &sum[rt][0]);
  52. sum[rt][1] = sum[rt][0] * sum[rt][0];
  53. return ;
  54. }
  55. LL m = (l + r) >> 1;
  56. Build(lson);
  57. Build(rson);
  58. PushUp(rt);
  59. }
  60. void Updata_Add(LL L, LL R, LL num, LL l, LL r, LL rt)
  61. {
  62. if(L <= l && r <= R)
  63. {
  64. sum[rt][1] += 2 * sum[rt][0] * num + (r - l + 1) * num * num;
  65. sum[rt][0] += (r - l + 1) * num;
  66. add[rt] += num;
  67. return ;
  68. }
  69. LL m = (l + r) >> 1;
  70. PushDown(m - l + 1, r - m, rt);
  71. if(L <= m)
  72. Updata_Add(L, R, num, lson);
  73. if(m < R)
  74. Updata_Add(L, R, num, rson);
  75. PushUp(rt);
  76. }
  77. void Updata_mul(LL L, LL R, LL num, LL l, LL r, LL rt)
  78. {
  79. if(L <= l && r <= R)
  80. {
  81. sum[rt][0] *= num;
  82. sum[rt][1] *= num * num;
  83. mul[rt] *= num;
  84. add[rt] *= num;
  85. return ;
  86. }
  87. LL m = (l + r) >> 1;
  88. PushDown(m - l + 1, r - m, rt);
  89. if(L <= m)
  90. Updata_mul(L, R, num, lson);
  91. if(m < R)
  92. Updata_mul(L, R, num, rson);
  93. PushUp(rt);
  94. }
  95. LL Query(LL L, LL R, LL l, LL r, LL rt, LL opt)
  96. {
  97. if(L <= l && r <= R)
  98. {
  99. if(opt == 1)
  100. return sum[rt][0];
  101. if(opt == 2)
  102. return sum[rt][1];
  103. }
  104. LL ans = 0;
  105. LL m = (l + r) >> 1;
  106. PushDown(m - l + 1, r - m, rt);
  107. if(L <= m)
  108. ans += Query(L, R, lson, opt);
  109. if(m < R)
  110. ans += Query(L, R, rson, opt);
  111. return ans;
  112. }
  113. int main()
  114. {
  115. Fil(mul, (MAXN << 2), 1);
  116. LL n, m;
  117. scanf("%d%d", &n, &m);
  118. Build(1, n, 1);
  119. while(m--)
  120. {
  121. LL opt, l, r, x;
  122. scanf("%d%d%d", &opt, &l, &r);
  123. if(opt == 1 || opt == 2)
  124. printf("%lld\n", Query(l, r, 1, n, 1, opt));
  125. else if(opt == 3)
  126. {
  127. scanf("%lld", &x);
  128. Updata_mul(l, r, x, 1, n, 1);
  129. }
  130. else
  131. {
  132. scanf("%lld", &x);
  133. Updata_Add(l, r, x, 1, n, 1);
  134. }
  135. }
  136. return 0;
  137. }

牛客练习赛28-B(线段树,区间更新)的更多相关文章

  1. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  2. hdu 1698 线段树 区间更新 区间求和

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  3. HDU3577 线段树(区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577 ,普通的线段树区间更新题目,较简单. 相当于一个区间覆盖问题,有一点要注意的就是叶子节点是一个长 ...

  4. HDU 1556 Color the ball(线段树区间更新)

    Color the ball 我真的该认真的复习一下以前没懂的知识了,今天看了一下线段树,以前只会用模板,现在看懂了之后,发现还有这么多巧妙的地方,好厉害啊 所以就应该尽量搞懂 弄明白每个知识点 [题 ...

  5. hihoCoder 1080 : 更为复杂的买卖房屋姿势 线段树区间更新

    #1080 : 更为复杂的买卖房屋姿势 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho都是游戏迷,“模拟都市”是他们非常喜欢的一个游戏,在这个游戏里面他们 ...

  6. HDU 5023 A Corrupt Mayor's Performance Art(线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色 ...

  7. HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是 ...

  8. HDU 1698 线段树 区间更新求和

    一开始这条链子全都是1 #include<stdio.h> #include<string.h> #include<algorithm> #include<m ...

  9. POJ-2528 Mayor's posters (线段树区间更新+离散化)

    题目分析:线段树区间更新+离散化 代码如下: # include<iostream> # include<cstdio> # include<queue> # in ...

随机推荐

  1. Matlab SLAM

    https://www.baidu.com/s?wd=Matlab%20SLAM&rsv_spt=1&rsv_iqid=0xfacaed5e00006d4e&issp=1&am ...

  2. Tango Java API常数

    Tango Java API Constants常数 Constant Field Values常数字段值 Contents com.google.* com.google.* com.google. ...

  3. 解决NIOS II工程移动在磁盘上位置后project无法编译问题

    说明:本文档于2017年3月4日由小梅哥更新部分内容,主要是增加了讲解以Quartus II13.0为代表的经典版本和以15.1为代表的更新版本之间,解决问题的一些小的差异. 如果用户只是想快速解决问 ...

  4. 6、Semantic-UI之动画按钮样式

    6.1 动画按钮样式 在Semantic-UI中提供了三种动画样按钮式表,分别为: 左右移动 上下移动 淡入淡出   在实际开发中,很少使用这种动画按钮,根据实际情况使用,强制使用到页面中反而不太适合 ...

  5. Linq的使用场景简介和认识

    一:C#的一个分支Linq 二:学Linq需要有一些基础知识 1. var 隐式类型 2. 匿名类型/匿名方法 3. 自动属性 4. 委托/泛型的委托 5. lambda 6. 扩展方法 7. 对象初 ...

  6. java状态模式

    核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线.隐身.忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1.可以通过改变状 ...

  7. Transaction And Lock--事务中使用return会回滚事务吗?

    事务中使用return会回滚事务吗? 答案:不会,如果在事务中没有显示提交或回滚事务边return,事务不会被提交或回滚,在C#中,如果没有使用连接池,则事务在连接断开和销毁时被强制回滚,如果使用连接 ...

  8. Windows7系统安装TensorFlow深度学习框架全过程

    本来以为很好安装的一个东西,硬是从晚上九点搞到十二点,安装其实并不难,主要是目前网上的教程有很多方案完全不一样,有根据pip安装的,有根据docker安装的等等,看得我眼花缭乱,好不容易找到一个靠谱点 ...

  9. occal [问题解决]ORA-01427: 单行子查询返回多个行

    有人问题我一个问题,情况如下:他要用根据divide_act_channel_day的new_amount字段去更新divide_stat的new_amount字段.两张表关联的条件:day=log_ ...

  10. [Perl]通过GD模块获取字符/汉字的点阵

    原来Perl获取汉字的点阵如此简单 示例脚本应保存为utf8格式 Code: [全选] [展开/收缩] [Download] (Untitled.pl) use GD; use utf8; my $g ...