线段树是ACM竞赛的常客,由于它的高效,美妙,经常被拿来出题。线段树是解决与区间有关的问题的,其中有一类问题就是更新区间上的一段值,这是非常典型的一类问题,在此,我做个小结。

倘若要更新一个区间的值,我们每次更新到叶子节点,那么这样效率就非常低了。倘若我们能每次只更新到你需要的节点,然后在该节点做个标记(就是lazy标记),下次要用到该节点下的东西,再更新下面的值。举一个经典例子,HDU1698。

Just a Hook

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 29463    Accepted Submission(s): 14555

Problem Description
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.

Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.

Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.
Sample Input
  
1 10 2 1 5 2 5 9 3
Sample Output
  
Case 1: The total value of the hook is 24.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <cctype>
#define LL long long
#define INF 0x7fffffff
using namespace std;const int maxn = 100005;int sum[maxn << 2];//求区间和
int lazy[maxn << 2];//延迟标记 void pushdown(int rt, int m) {if(lazy[rt]) {//如果之前这里做了标记,则说明没有往下更新,暂停了一下,用来判断是否需要往下更新 lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];sum[rt << 1] = (m - (m >> 1)) * lazy[rt];sum[rt << 1 | 1] = (m >> 1) * lazy[rt];lazy[rt] = 0;//往下更新完后,标记置为0,即当前不需要往下更新 }
}void build(int l, int r, int rt) {lazy[rt] = 0;sum[rt] = r - l + 1;if(l == r) return;int mid = (l + r) >> 1;build(l, mid, rt << 1);build(mid + 1, r, rt << 1 | 1);
}void update(int L, int R, int c, int l, int r, int rt) {if(L <= l && r <= R) {sum[rt] = c * (r - l + 1);lazy[rt] = c;//延迟标记,每次把该段更新完后暂时不往下更新,节省时间,这里特别注意和累加的区别,累加是为整个区间增加多少值 return;}pushdown(rt, r - l + 1);//向下更新 int mid = (l + r) >> 1;if(L <= mid) update(L, R, c, l, mid, rt << 1);if(R >= mid + 1) update(L, R, c, mid + 1, r, rt << 1 | 1);sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];//向上更新
}int main() {int T, n, m;scanf("%d", &T);for(int cas = 1; cas <= T; cas ++) {scanf("%d %d", &n, &m);build(1, n, 1);for(int i = 0; i < m; i ++) {int a, b, c;scanf("%d %d %d", &a, &b, &c);update(a, b, c, 1, n, 1);}printf("Case %d: The total value of the hook is %d.\n", cas, sum[1]);}return 0;
}

当然,有些时候选择更新到那个节点,做了标记之后要怎么再往下更新,还是得靠点脑洞的。

Can you answer these queries?

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 14238    Accepted Submission(s): 3317

Problem Description
A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help.
You are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line.

Notice that the square root operation should be rounded down to integer.

Input
The input contains several test cases, terminated by EOF.
  For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000)
  The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. You can assume that the sum of all endurance value is less than 2 63.
  The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000)
  For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive.
Output
For each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.
Sample Input
  
10 1 2 3 4 5 6 7 8 9 10 5 0 1 10 1 1 10 1 1 5 0 5 8 1 4 8
Sample Output
  
Case #1: 19 7 6
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 100010;LL sum[maxn*4];
int n, m;void PushUp(int rt)
{sum[rt] = sum[rt<<1] + sum[rt<<1|1];return ;
}void build(int l, int r, int rt)
{sum[rt] = 0;if(l == r){scanf("%I64d", &sum[rt]);return ;}int m = (l+r)>>1;build(lson);build(rson);PushUp(rt);
}void update(int L, int R, int l, int r, int rt)
{if(l == r){sum[rt] = sqrt(1.0 * sum[rt]);return ;}if(L<=l && r<=R && sum[rt]==r-l+1)  //此时每个数都为1  没必要更新 {return ;}int m = (l+r)>>1;if(L <= m) update(L, R, lson);if(m < R) update(L, R, rson);PushUp(rt);
}LL query(int L, int R, int l, int r, int rt)
{if(L<=l && r<=R){return sum[rt];}int m = (l+r)>>1;LL ans = 0;if(L <= m)   ans += query(L, R, lson);if(m < R)    ans += query(L, R, rson);return ans;
}int main()
{int test = 0;while(scanf("%d", &n) != EOF){build(1, n, 1);int a, b, c;int x, y;scanf("%d", &m);printf("Case #%d:\n", ++test);while(m--){scanf("%d%d%d", &a, &b, &c);x = min(b, c);y = max(b, c);if(a == 0){update(x, y, 1, n, 1);}else{printf("%I64d\n", query(x, y, 1, n, 1));}}puts("");}return 0;
}

线段树(区间更新)小结相关推荐

  1. hdu 5692 Snacks(dfs序+线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692 解题思路:这道题是树节点的点权更新,而且涉及到子树,常用的思路是利用dfs序,用线段树来对区间进 ...

  2. hdu 1698(线段树区间更新)

    解题思路:线段树区间更新水题. #include<iostream> #include<cstdio> #include<cstring> using namesp ...

  3. ZOJ 1610 Count the Colors (线段树区间更新)

    题目链接 题意 : 一根木棍,长8000,然后分别在不同的区间涂上不同的颜色,问你最后能够看到多少颜色,然后每个颜色有多少段,颜色大小从头到尾输出. 思路 :线段树区间更新一下,然后标记一下,最后从头 ...

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

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

  5. POJ 2777 ZOJ 1610 HDU 1698 --线段树--区间更新

    直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 ...

  6. Just a Hook(线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 In the game of DotA, Pudge's meat hook is actual ...

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

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

  8. CodeForces - 272C Dima and Staircase (线段树区间更新)

    题意: 见以下样例,给出 5 个区间,每个区间的高度已知.一共 4 次操作.每次操作都是从最左边开始向下垒一个宽为 w 高为h 的木块,过程见下图. 问每次垒木块的高度是多少? Input 5 1 2 ...

  9. CDOJ-1057 秋实大哥与花(线段树区间更新)

    秋实大哥与花 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit St ...

最新文章

  1. ListT随机返回一个
  2. CCNp笔记(EIGRP)
  3. 开源代码却无奈遗弃,濒临奔溃的开源开发者们!
  4. mysql sql left right inner join区别及效率比较
  5. GDI+中常见的几个问题(6)
  6. 神圣的NLP!一文理解词性标注、依存分析和命名实体识别任务
  7. ubuntu中用wine安装office2007
  8. 将html代码转换为dom,将HTML字符转换为DOM节点并动态添加到文档中
  9. 【01背包】洛谷P1282多米诺骨牌
  10. 工具类与工具函数 —— 素数相关
  11. 【java笔记】常用函数式接口(3):Predicate接口
  12. 小旭追女神-三国乱世(裸的单点线段树更新)
  13. 毕业设计开发日志,基于ARM的嵌入式人脸识别系统的设计与实现
  14. JUC- 常用的辅助类
  15. c语言计算个人成绩平均分,C语言 | 计算总平均分及第n个人的成绩
  16. html 布局 flex,CSS flex布局
  17. JZOJ5498. 【清华集训2017模拟12.10】大佬的难题
  18. word表格导出html代码,(网页源代码中的表格数据怎么导出excel)如何将把从WORD、EXCEL中复制的内容转换成HTML源代码,再通过网页表单提交上传到数据库?...
  19. linux下安装grads
  20. python+ pyqt5 实现最简单的计算器

热门文章

  1. 新认知,python爬取12306火车出行时间
  2. Oracle Explan
  3. (1) Apache POI 概述
  4. Python 错误 SyntaxError: Non-ASCII character ‘\xe4‘ in file
  5. 软件测试信息采集系统案例实践,软件测试课件.ppt
  6. Matlab fmincon
  7. git命令行常用命令
  8. PHP多进程 - Yac扩展的基本原理及其使用教程(cli和fpm)
  9. 冰糖橙水果文案朋友圈,水果冰糖橙文案
  10. FAQ-MT6250/MT6250D平台,FM外放时耳机无声