线段树区间修改模板

本来打算把大白书第三章一口气攻下来的,但是这个线段树也是卡了好久。

不敢过题太快,怕自己走马观花到头来结果什么都不会。

可也不能再拖了,在做题中也许有更多的体会。

模板一:
1 L R v 表示区间[L, R]所有元素都加上v
2 L R   表示查询区间[L, R]的sum, min, max
sumv[o]的定义为:如果只执行节点o及其子孙节点的中的add操作,节点o对应区间中所有数之和

 1 //线段树区间修改
 2 //1 L R v 表示区间[L, R]所有元素都加上v
 3 //2 L R   表示查询区间[L, R]的sum, min, max
 4 //sumv[o]的定义为:如果只执行节点o及其子孙节点的中的add操作,节点o对应区间中所有数之和
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <algorithm>
 8 using namespace std;
 9
10 const int maxnode = 1 << 17;
11
12 int _sum, _min, _max, op, qL, qR, v;
13
14 struct IntervalTree
15 {
16     int sumv[maxnode], minv[maxnode], maxv[maxnode], addv[maxnode];
17
18     //维护信息
19     void maintain(int o, int L, int R)
20     {
21         int lc = o*2, rc = o*2+1;
22         if(R > L)
23         {
24             sumv[o] = sumv[lc] + sumv[rc];
25             minv[o] = min(minv[lc], minv[rc]);
26             maxv[o] = max(maxv[lc], maxv[rc]);
27         }
28         if(addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+1); }
29     }
30
31     void update(int o, int L, int R)
32     {
33         int lc = o*2, rc = o*2+1;
34         if(qL <= L && R <= qR) addv[o] += v;
35         else
36         {
37             int M = (L + R) / 2;
38             if(qL <= M) update(lc, L, M);
39             if(qR > M) update(rc, M+1, R);
40         }
41         maintain(o, L, R);
42     }
43
44     void query(int o, int L, int R, int add)
45     {
46         if(qL <= L && R <= qR)
47         {
48             _sum += sumv[o] + add * (R-L+1);
49             _min = min(_min, minv[o] + add);
50             _max = max(_max, maxv[o] + add);
51         }
52         else
53         {
54             int M = (L + R) / 2;
55             if(qL <= M) query(o*2, L, M, add + addv[o]);
56             if(qR > M) query(o*2+1, M+1, R, add + addv[o]);
57         }
58     }
59 }tree;
60
61 const int INF = 1000000000;
62
63 int main()
64 {
65     int n, m;
66     while(scanf("%d%d", &n, &m) == 2)
67     {
68         memset(&tree, 0, sizeof(tree));
69         while(m--)
70         {
71             scanf("%d%d%d", &op, &qL, &qR);
72             if(op == 1) { scanf("%d", &v); tree.update(1, 1, n); }
73             else
74             {
75                 _sum = 0; _min = INF; _max = -INF;
76                 tree.query(1, 1, n, 0);
77                 printf("%d %d %d\n", _sum, _min, _max);
78             }
79         }
80     }
81
82     return 0;
83 }

代码君

模板二:

线段树区间修改set
1 L R v 表示将区间[L, R]全部赋值为v (v >= 0)
2 L R   表示查询区间[L, R]的sum, min, max

  1 //线段树区间修改set
  2 // 1 L R v 表示将区间[L, R]全部赋值为v (v >= 0)
  3 // 2 L R   表示查询区间[L, R]的sum, min, max
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <algorithm>
  7 using namespace std;
  8
  9 const int maxnode = 1 << 17;
 10
 11 int _sum, _min, _max, op, qL, qR, v;
 12
 13 struct IntervalTree
 14 {
 15     int sumv[maxnode], minv[maxnode], maxv[maxnode], setv[maxnode];
 16
 17     //维护信息
 18     void maintain(int o, int L, int R)
 19     {
 20         int lc = o*2, rc = o*2;
 21         if(R > L)
 22         {
 23             sumv[o] = sumv[lc] + sumv[rc];
 24             minv[o] = min(minv[lc], minv[rc]);
 25             maxv[o] = max(maxv[lc], maxv[rc]);
 26         }
 27         if(setv[o] >= 0) { minv[o] = maxv[o] = setv[o]; sumv[o] = (R-L+1) * setv[o]; }
 28     }
 29
 30     //标记传递
 31     void pushdown(int o, int L, int R)
 32     {
 33         int lc = o*2, rc = o*2+1;
 34         if(setv[o] >= 0)//-1表示没有标记过节点
 35         {
 36             setv[lc] = setv[rc] = setv[o];
 37             setv[o] = -1;//清除本节点的标记
 38         }
 39     }
 40
 41     void update(int o, int L, int R)
 42     {
 43         int lc = o*2, rc = o*2+1;
 44         if(qL <= L && R <= qR) setv[o] = v;
 45         else
 46         {
 47             pushdown(o, L, R);
 48             int M = (L + R) / 2;
 49             if(qL <= M) update(lc, L, M); else maintain(lc, L, M);
 50             if(qR > M) update(rc, M+1, R); else maintain(rc, M+1, R);
 51         }
 52         maintain(o, L, R);
 53     }
 54
 55     void query(int o, int L, int R)
 56     {
 57         if(setv[o] >= 0)//递归边界1:有set标记
 58         {
 59             _sum += setv[o] * (min(R, qR) - max(L, qL) + 1);
 60             _min = min(_min, setv[o]);
 61             _max = max(_max, setv[o]);
 62         }
 63         else if(qL <= L && R <= qR)
 64         {//递归边界2:边界区间,此区间没有收到set影响
 65             _sum += sumv[o];
 66             _min = min(_min, minv[o]);
 67             _max = max(_max, maxv[o]);
 68         }
 69         else
 70         {//递归统计
 71             int M = (L + R) / 2;
 72             if(qL <= M) query(o*2, L, M);
 73             if(qR > M) query(o*2+1, M+1, R);
 74         }
 75     }
 76 }tree;
 77
 78 const int INF = 1000000000;
 79
 80 int main()
 81 {
 82     int n, m;
 83     while(scanf("%d%d", &n, &m) == 2)
 84     {
 85         memset(&tree, 0, sizeof(tree));
 86         memset(tree.setv, -1, sizeof(tree.setv));
 87         tree.setv[0] = 1;
 88         while(m--)
 89         {
 90             scanf("%d%d%d", &op, &qL, &qR);
 91             if(op == 1) { scanf("%d", &v); tree.update(1, 1, n); }
 92             else
 93             {
 94                 _sum = 0; _min = INF; _max = -INF;
 95                 tree.query(1, 1, n);
 96                 printf("%d %d %d\n", _sum, _min, _max);
 97             }
 98         }
 99     }
100
101     return 0;
102 }

代码君

时间: 2024-10-14 05:52:22

线段树区间修改模板的相关文章

【模板】线段树区间修改

区间修改: 区间修改过程类似于区间询问,例如将[ul, ur]内的所有元素都加上v,则进行如下操作: 当当前区间被区间[ul, ur]所包含时, 当前的节点值加上区间长度(r - l  + 1)乘以v 对当前节点的lazy-tag加上v,修改结束 否则,将当前节点的lazy-tag下传,分别修改左孩子和右孩子(一定条件下),然后更新此节点的值 lazy-tag下传: 如果当前节点没有lazy-tag,直接return 否则:1. 将左孩子右孩子分别加上lazy-tag * 区间长度的值  2.

hdu1698 Just a Hook(线段树+区间修改+区间查询+模板)

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 54923    Accepted Submission(s): 25566 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of

线段树区间修改 P3372 【模板】线段树 1

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包含若干行整

poj 2777 Count Color(线段树区间修改)

题目链接:http://poj.org/problem?id=2777 题目意思:就是问你在询问的区间里有几种不同的颜色 思路:这题和一般的区间修改差不多,但是唯一不同的就是我们要怎么计算有种颜色,所以这时候我们就需要把延时标记赋予不同的意义,当某段区间有多种颜色时就赋值为-1,当为一种颜色时就把它赋值为这个颜色的号数.这儿我们要怎么统计询问区间不同的颜色数叻,为了不重复计算同一种颜色,那么我们就需要用一个数组来标记计算过的颜色,当我们下次遇到时就不需要再次计算了.... 代码核心处就在计数那儿

hdu-5023 A Corrupt Mayor&#39;s Performance Art (线段树区间修改)

今天集训队打比赛的一道题,很明显是个线段树,我们队照着lrj蓝书敲了一通,机智的将修改值和加和改成了位运算:|= 但是好像哪里出了点小问题,就是不对,赛后又水了一遍,竟然过了...发现还是lrj的书好啊,市面上的模板一点也不好用,连区间修改都没有 . 等集训完了要静心好好系统的学习一下线段树 . 多看多刷lrj的书 . 细节参见代码: #include<bits/stdc++.h> using namespace std; const int maxn = 1000000 + 5; int n

HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)

思路:本题因为是点修改,所以我们可以用线段树或者是树状数组了.线段树的基本操作我在我的代码中会具体体现,关键是要理解下面这幅图,具体的思想大家可以去看看其他的资料 线段树AC代码: #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define N 50005 int num

【线段树区间修改】fzu2105Digits Count

/* 题意: 给出数组A,有以下几个操作: 1: AND(opn, L, R):把区间[L, R]中的元素A[i]改为A[i] & opn;;;;;; 2: OR(opn, L, R) :把区间[L, R]中的元素A[i]改为A[i] | opn;;;;;;; 3: XOR(opn, L, R):把区间[L, R]中的元素A[i]改为A[i] ^ opn;;;;;;; 4: SUM(L, R) :对区间[L, R]中的元素求和:::: ------------------------------

线段树 + 区间更新 + 模板 ---- poj 3468

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 59798   Accepted: 18237 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

Wikilo 1191线段树区间修改单点查询

这题也算比较容易的了. 如果哪个区间已经没有黑色的话,就不用update了,就是因为这个原因WA了2发,唉-- #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #incl