线段树
线段树
概念
其实就是一个二叉树,运用了分治的思想。将一个有序数组从中间截断,并不断的截,直到最后每组只剩单一元素时即可,由于可以方便的进行区间修改和区间求和,于是叫做线段树
建树
思路: 先确定边界条件,即\(L=R\)时,在线段树上添加结点,否则就把区间截成两段,再次进行操作。代码如下:
void build(int l, int r, int t)//建树
{
if (l == r)
{
w[l] = s[t]; //赋值
return ;
}
int mid = (l + r) / 2;//在中间找中点
//注意记号加一(t)
build(l, mid, ++t);//左边建树(l~mid)
build(mid + 1, r, ++t);//右边建树(mid+1~r)
s[t] = s[2 * t] + s[2 * t + 1];//线段树性质,
}
更改
void update(int l, int r, int c, int s, int t, int p)//更新
{
if (l <= s && t <= r)
{
b[p] += (t - s + 1) * c;
lazy_tag[p] += c;
return;
}
int m = (s + t) / 2;
if (lazy_tag[p] && s != t)
{
b[p * 2] += lazy_tag[p] * (m - s + 1);
b[p * 2 + 1] += lazy_tag[p] * (t - m);
lazy_tag[p * 2] += lazy_tag[p];
lazy_tag[p * 2 + 1] += lazy_tag[p];
lazy_tag[p] = 0;
}
if (l <= m)
{
update(l, r, c, s, m, p * 2);
}
if (r > m)
{
update(l, r, c, m + 1, t, p * 2 + 1);
}
b[p] = b[p * 2] + b[p * 2 + 1];
}
求和
思路: 就是在一个区间中查找另一区间,不断缩短搜索范围,直到完全匹配就返回答案,否则在左右两边判断是否含有当前部分。代码如下:
void getsum(int L, int R, int l, int r, int t)//求和
{
if (L <= l && R <= r)
{
return s[t];//找到区间了,就返回
}
int mid = l + (r - l) / 2;//找到中点
int sum = 0;//定义和,初始为0
if (l <= mid)//如果在左区间有部分
{
sum += getsum(L, R, l, mid, p * 2);//把区间截断,只留左边继续递归,并把和累加
}
if (r > mid)//如果再右区间有部分
{
sum += getsum(L, R, mid + 1, r, p * 2 + 1);//把区间截断,只留右边继续递归,并把和累加
}
}

浙公网安备 33010602011771号