线段树
【摘要】
简单线段树过程详解
#include<iostream> //——————————>debug 了一上午才把这个程序运行的过程在脑子里有了思路
#include<s...
简单线段树过程详解
#include<iostream> //——————————>debug 了一上午才把这个程序运行的过程在脑子里有了思路
#include<string.h> //头文件就不多说了
#include<stdlib.h>
#define maxsize 10000 //这个可定义其他数----------->这个 主要是控制数组的大小,
using namespace std;
struct node { //结构体 ,相当于创建的二叉树
int left, right; //记录的左右子节点
int lazy, sum; //lazy记录延迟,sum记录在这个节点的左右端点之间的总和
int mid() { return (left + right) / 2; }
}T[maxsize<<2];//相当于扩大了4倍----------------------->这个时学过数据结构的都知道度为0的比度为2的多1有n个数说明n个叶子节点要建立2*n-1个点但是
//因为假若数据相对较大,则访问到了最后一行,则可能用到 n<<1 这种情况就会越界会re所以开4倍
void pushup(int rt) //向上更新sum的值
{
T[rt].sum = T[rt << 1].sum + T[rt << 1 | 1].sum;
}
void pushdown(int rt, int m) //向下更新lazy和sum的值,主意好区间,因为整篇都是做区间的多于右区间
{
if (T[rt].lazy)
{
T[rt << 1].lazy += T[rt].lazy;
T[rt << 1 | 1].lazy += T[rt].lazy; //更新lazy值
T[rt<<1].sum += T[rt].lazy*(m - (m >> 1));//这说明如果是n为奇数 则左半部分就是多1
T[rt<<1|1].sum += T[rt].lazy *(m >> 1);//注意>>的优先级
T[rt].lazy = 0; //不能忘了把这个标志置为0
}
}
void create(int rt, int l, int r)
{
T[rt].left = l; //创建时对左节点和右节点进行赋值
T[rt].right = r;
T[rt].lazy = 0;
if (T[rt].left == T[rt].right) //不能写下边了,且只有当到也叶子节点时也就是当节点的左边等于右边时才赋值
{ //不然地址就错了 ,因为递归调用返回时输入值的地址i就是错的
cin >> T[rt].sum; //或是赋值为0,
return;
}
create(rt << 1, l, T[rt].mid()); //这个创建进过摸你可以看出如果n为奇数返回的中间值时中间的奇数,则说明创建的时候左边可能比右边的多
create(rt << 1 | 1, T[rt].mid()+1, r); //不能忘记mid()+1
pushup(rt); //创建完之后别忘了向上传递更新上边的sum值
}
void Union(int rt, int l, int r, int c)//rt 为根节点,在l和r的范围内部的数都加上c
{
if (T[rt].left == l&&T[rt].right == r) //这里就用到lazy做延迟了,这个节点lazy记录的是这个区间内要加的但是不向下进行了,
{ //就省了时间,sum记录的是这个姐弟啊你左右端点内的所有要加的值的和
T[rt].lazy += c;
T[rt].sum += c*(T[rt].right - T[rt].left + 1); //
return;
}
if (T[rt].left == T[rt].right) return;
pushdown(rt, T[rt].right - T[rt].left + 1);
if (r <= T[rt].mid()) //因为如果为奇数,则返回的中间值时中间的奇数,
Union(rt << 1, l, r, c);
else if (l > T[rt].mid())
Union(rt << 1 | 1, l, r, c);
else {
Union(rt << 1, l, T[rt].mid(), c);
Union(rt << 1 | 1, T[rt].mid()+1, r, c);
}
pushup(rt); //这个是向上更新,其实就是用下边的两个点来更新这个点
}
int sum(int rt, int l, int r)//求出在某个范围l到r内的和
{
int ans=0;
if (T[rt].left == l&&T[rt].right==r) //看好代码别写错了
return T[rt].sum;
pushdown(rt, T[rt].right - T[rt].left + 1);
if (r <= T[rt].mid()) /这个必须是小于等于因为 若是奇数则返回的时中间的奇数则就是返回的数比另一半多1,所以就小于等于
ans+=sum(rt << 1, l, r);
else if (l >T[rt].mid())
ans+=sum(rt << 1 | 1, l, r);
else {
ans+=sum(rt << 1, l, T[rt].mid());
ans+=sum(rt << 1 | 1, T[rt].mid()+1, r);//不要忘记是mid()+1;
}
return ans;
}
int main()
{
int n, m, a, b, c;
while (cin >> n >> m)
{
create(1,1,n);
while (m--)
{
char s;
cin >> s;
if (s == 'Q') //查询在a,b区间的总和
{
cin >> a >> b;
cout << sum(1, a, b)<<endl;
}
else if(s=='B'){ //在 a,b区间内每个节点都加上c
cin >> a >> b >> c;
Union(1, a, b, c);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
文章来源: englishcode.blog.csdn.net,作者:知识浅谈,版权归原作者所有,如需转载,请联系作者。
原文链接:englishcode.blog.csdn.net/article/details/80009137
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)