线段树(二)

第一篇以一道简单的题目为背景介绍了线段树的基本结构和基本性质,这一篇我们使用线段树来解决几个常见的问题

1. 查询区间最大(小)值

支持两种操作:a. 修改某个点的值

b. 查询某个区间的最大(小)值

 1 #include <stdio.h>
 2 #define N 1024
 3
 4 typedef struct {
 5     int min_value;
 6     int left;
 7     int right;
 8 } ST;
 9
10 int  input[N + 1];
11 int father[N + 1];
12 ST  st[N * 2 + 1];
13
14
15 /* 查询 */
16 int query_ST(int i, int left, int right) {
17     if(left == right) {
18         return st[father[left]].min_value;
19     }
20     int l = st[i].left;
21     int r = st[i].right;
22     if(l == left && r == right) {
23         return st[i].min_value;
24     }
25     else if(right <= (r + l) / 2) {
26         return query_ST(i * 2, left, right);
27     }
28     else if(left > (r + l) / 2) {
29         return query_ST(i * 2 + 1, left, right);
30     }
31     else {
32         int min_l = query_ST(i * 2, left, (l + r) / 2);
33         int min_r = query_ST(i * 2 + 1, (l + r) / 2 + 1, right);
34         return  min_l = min_l < min_r ? min_l : min_r;
35     }
36 }
37
38 /* 修改 */
39 void modify_ST(int pos, int value) {
40     int i = father[pos];
41     int min_l, min_r;
42     st[i].min_value = value;
43     i = i / 2;
44     while(i) {
45         min_l = st[i * 2].min_value;
46         min_r = st[i * 2 + 1].min_value;
47         min_l = min_l < min_r ? min_l : min_r;
48         if(st[i].min_value == min_l) break;
49         st[i].min_value = min_l;
50         i = i / 2;
51     }
52 }
53
54 /* 建树 */
55 int build_ST(int i, int left, int right) {
56     st[i].left = left;
57     st[i].right = right;
58     if(left == right) {
59         father[left] = i;
60         st[i].min_value = input[left];
61         return input[left];
62     }
63     int min_l = build_ST(i * 2, left, (left + right) / 2);
64     int min_r = build_ST(i * 2 + 1, (left + right) / 2 + 1, right);
65     min_l = min_l < min_r ? min_l : min_r;
66     return st[i].min_value = min_l;
67 }
68
69 int main() {
70     int m, n;
71     int b_mod, left, right;
72     scanf("%d", &n);
73     for(int i = 0; i < n; i++) {
74         scanf("%d", &input[i]);
75     }
76     scanf("%d", &m);
77     build_ST(1, 0, n - 1);
78     for(int i = 0; i < m; i++) {
79         scanf("%d %d %d", &b_mod, &left, &right);
80         if(b_mod) { modify_ST(left - 1, right); }
81         else { printf("%d\n", query_ST(1, left - 1, right - 1)); }
82     }
83     return 0;
84 }

2.  查询区间和(乘积)值

支持两种操作:a. 修改某个点的值

b. 查询某个区间的和

这里使用了lazy的思想,即查询时更新

  1 #include <stdio.h>
  2 #define N 1024 * 1024
  3
  4 typedef struct {
  5     int left;
  6     int righ;
  7     int lazy;
  8     int sum;
  9 }st_node;
 10
 11 st_node st[N + 1];
 12 int  seg[2 * N + 1];
 13
 14 int build_st(int i, int left, int righ) {
 15     st[i].left = left;
 16     st[i].righ = righ;
 17     if(left == righ) {
 18         st[i].sum = seg[left];
 19         st[i].lazy = -1;
 20         return st[i].sum;
 21     }
 22     int l_sum = build_st(i * 2, left, (left + righ) / 2);
 23     int r_sum = build_st(i * 2 + 1, (left + righ) / 2 + 1, righ);
 24     st[i].sum = l_sum + r_sum;
 25     st[i].lazy = -1;
 26     return l_sum + r_sum;
 27 }
 28 int modify_st(int i, int left, int righ, int value) {
 29     if(st[i].left == left && st[i].righ == righ) {
 30         st[i].lazy = value;
 31         st[i].sum = (righ + 1 - left) * value;
 32         return st[i].sum;
 33     }
 34     else {
 35         if(-1 != st[i].lazy) {
 36             int l_len = st[i * 2].righ + 1 - st[i * 2].left;
 37             st[i * 2].lazy = st[i].lazy;
 38             st[i * 2].sum = l_len * st[i * 2].lazy;
 39
 40             int r_len = st[i * 2 + 1].righ + 1 - st[i * 2 + 1].left;
 41             st[i * 2 + 1].lazy = st[i].lazy;
 42             st[i * 2 + 1].sum = r_len * st[i * 2 + 1].lazy;
 43
 44             st[i].lazy = -1;
 45         }
 46         int l = st[i].left;
 47         int r = st[i].righ;
 48         int l_sum = st[i * 2].sum;
 49         int r_sum = st[i * 2 + 1].sum;
 50         if(righ <= (r + l) / 2) {
 51             l_sum = modify_st(i * 2, left, righ, value);
 52         }
 53         else if(left > (r + l) / 2) {
 54             r_sum = modify_st(i * 2 + 1, left, righ, value);
 55         }
 56         else {
 57             l_sum = modify_st(i * 2, left, (l + r) / 2, value);
 58             r_sum = modify_st(i * 2 + 1, (l + r) / 2 + 1, righ, value);
 59         }
 60         st[i].sum= l_sum + r_sum;
 61         return st[i].sum;
 62     }
 63 }
 64
 65 int query_st(int i, int left, int righ) {
 66     if(st[i].left == left && st[i].righ == righ) {
 67         return st[i].sum;
 68     }
 69     else {
 70         if(-1 != st[i].lazy) {
 71             int l_len = st[i * 2].righ - st[i * 2].left + 1;
 72             st[i * 2].lazy = st[i].lazy;
 73             st[i * 2].sum = l_len * st[i * 2].lazy;
 74
 75             int r_len = st[i * 2 + 1].righ + 1 - st[i * 2 + 1].left;
 76             st[i * 2 + 1].lazy = st[i].lazy;
 77             st[i * 2 + 1].sum = r_len * st[i * 2 + 1].lazy;
 78
 79             st[i].lazy = -1;
 80         }
 81         int l = st[i].left;
 82         int r = st[i].righ;
 83         int l_sum = 0;
 84         int r_sum = 0;
 85         if(righ <= (r + l) / 2) {
 86             l_sum = query_st(i * 2, left, righ);
 87         }
 88         else if(left > (r + l) / 2) {
 89             r_sum = query_st(i * 2 + 1, left, righ);
 90         }
 91         else {
 92             l_sum = query_st(i * 2, left, (l + r) / 2);
 93             r_sum = query_st(i * 2 + 1, (l + r) / 2 + 1, righ);
 94         }
 95         return l_sum + r_sum;
 96     }
 97 }
 98
 99 int main() {
100     int i, n, m;
101     scanf("%d", &n);
102     for(i = 1; i <= n; i++) {
103         scanf("%d", &seg[i]);
104     }
105     build_st(1, 1, n);
106     scanf("%d", &m);
107     for(i = 0; i < m; i++) {
108         int mode;
109         int left;
110         int righ;
111         int value;
112         scanf("%d", &mode);
113         if(mode) {
114             scanf("%d %d %d", &left, &righ, &value);
115             modify_st(1, left, righ, value);
116         }
117         else {
118             scanf("%d %d", &left, &righ);
119             printf("%d\n", query_st(1, left, righ));
120         }
121     }
122     return 0;
123 }

3. 线段投影长度

时间: 2024-10-04 22:47:59

线段树(二)的相关文章

HDU6638 Snowy Smile (线段树+二维最大子段和)

2019杭电多校第六场的一道签到题 这次我们显然要求的二维矩阵的最大值,分析题目我们可以得到几个细节. 1.首先数据很大,肯定要离散化. 2.离散化后,我们想象有很多点在一个平面内,要统计矩阵最大值 3.我们之前接触过如何求一条线上的最大子段和,只要用线段树维护四个值就能够解决 4.根据已知,我们发现求矩阵和也是可以这么做的,因为他是一个矩形,所以我们假如我们有两行,其实可以把第二行的对应数据加到第一行上去,进行压维操作,再求一维的最大子段和. 5.我们要考虑所有的情况,因此我们以x轴作为线段树

CF1321-World of Darkraft: Battle for Azathoth (线段树+二维偏序)

题意: 题目大致意思是给你n把武器,m件防具,p个怪兽,接下来n行每行告诉你该武器的攻击力和花费, 接下来m行告诉你该防具的防御力和花费,然后p行每行告诉你这个怪兽的攻击力,防御力以及打败这个 怪兽可以获得的金钱数,当你的攻击力大于怪兽的防御力,并且你的防御力大于怪兽的攻击力时,你可 以打败这个怪兽.你必须至少购买1件武器和1件防具,问你最多可以获得多少钱. 链接:https://codeforces.com/contest/1321/problem/E 思路: 看了大神的题解,第一次知道二维偏

线段树&#183;二

1.UVA 11525 Permutation 题意:求1~k这k个数中第N个排列.(N从0开始记).N=sum(Si*(k-i)!)(1≤i≤k) 思路:根据N的值的性质,联系康拓展开,不妨发现第i位的值为剩下没用的数中从小到大第Si+1个.可以用线段树来记录区间内没有用的数的个数. 1 #include<iostream> 2 using namespace std; 3 int k; 4 const int maxk = 50010; 5 int numk[maxk]; 6 int tr

线段树の二 区间乘+区间加

具体就不解释了,看上一篇文章 放代码 注意点:!!!! 注意运算符优先级 比如: a*=b%p 是b先mod p再与a相乘 参见:https://baike.baidu.com/item/%E8%BF%90%E7%AE%97%E7%AC%A6%E4%BC%98%E5%85%88%E7%BA%A7/4752611?fr=aladdin /******************************* 线段树V2.0 支持区间加.区间乘.区间和查询 *************************

线段树二(区间修改)

概述 区间修改即将一个区间内所有值改为一个值(或加上一个值),为了执行快速,我们通常用"懒"标记维护整个区间值的情况,在需要是再将这个"懒"标记传到该节点的两个子节点上. 模版(此为在整个区间上加上一个值)(洛谷p3372) #include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#inclu

Luck and Love(二维线段树)

Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 54 Accepted Submission(s): 21   Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘

论线段树:二

<论线段树> ——线段树精细讲解第二篇   ——Yeasion_Nein出品 ><论线段树:一> ><论线段树:二> 在上一节中,我们大概了解了线段树的运算机制以及基本的代码运行 ,在这一节,我们主要针对一个例题进行更深层次的讲解. 首先来看一道题.(题目原链接:线段树2 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第

HDU1823-Luck and Love-二维线段树(模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1823 好吧,给这题跪了...orz.... 一道很基础的二维线段树的模板题: 但是细节很多:尤其注意了: swap函数会丢失精度,用double就等着WA到死吧...orz... 还有就是给你的区间不一定是按顺序的,得加一个判断:真的是坑...orz.... #include<iostream> #include<string> #include<cstdio> #incl

[IOI2018]werewolf狼人——kruskal重构树+可持久化线段树

题目链接: IOI2018werewolf 题目中编号都是从0开始,太不舒服了,我们按编号从1开始讲QAQ. 题目大意就是询问每次从一个点开始走只能走编号在[l,n]中的点,在任意点变成狼,之后只能走[0,r]中的点,是否能到达另一个点. 后一部分其实就是找有哪些点只走[0,r]中的点能到达终点,那么反过来看,就是终点只走[0,r]中的点能到达哪些点. 那么只要起点能到达的点和终点能到达的点中有交集就有解. 因为起点只能走一些编号较大的点,那么我们求出原图的最大生成树,建出kruskal重构树,