#include<stdio.h>
#include<stdlib.h>
int N, Q;
typedef struct node {
int l, r;
long long int sum;
long long int add;
}Node;
Node* Tree;
int* nums;
void build(int k, int l, int r)//k表示存储下表(结点下标),维护数组区间[l,r];
{
Tree[k] = { l,r,nums[l],0 };
if (l == r)//叶子
return;
int mid = (l + r) / 2;
build(2 * k, l, mid);
build(2 * k+ 1, mid + 1, r);
Tree[k].sum = Tree[2 * k].sum + Tree[2 * k + 1].sum;
}
void Pushdown(int k)//向下更新,懒标记
{
if (Tree[k].add)
{
Tree[2 * k].sum += Tree[k].add * (Tree[2 * k].r - Tree[2 * k].l + 1);
Tree[2 * k + 1].sum += Tree[k].add * (Tree[2 * k + 1].r - Tree[2 * k + 1].l + 1);
Tree[2 * k].add += Tree[k].add;
Tree[2 * k + 1].add += Tree[k].add;
Tree[k].add = 0;
}
}
void update(int k, int l, int r, int num)//修改区间内的值
{
if (l <= Tree[k].l && Tree[k].r <= r)
{
Tree[k].sum += (Tree[k].r - Tree[k].l+1) * num;
Tree[k].add += num;//直接覆盖区间,标记懒标记
return;
}
//未覆盖,先还帐
//如果修改区间位完全覆盖,则需要向下,若遇到之前的懒标记要向把孩子节点标记懒标记
Pushdown(k);//向下调整,先还账
int mid = (Tree[k].l + Tree[k].r) / 2;
if (l <= mid)//分裂
update(2 * k, l, r, num);
if (mid < r)
update(2 * k + 1, l, r, num);
Tree[k].sum = Tree[2 * k].sum + Tree[2 * k + 1].sum;//回溯向上调整
}
//void change(int k, int x, int num)//点更新,k根结点,x 为原数组修改位置,num修改为的值
//{
// if (Tree[k].l == x && Tree[k].r == x)
// {
// Tree[k].sum += num;
// return;
// }
// int mid = (Tree[k].l + Tree[k].r) / 2;
// if (x <= mid)
// change(2*k, x, num);
// if (mid < x)
// change(2 * k + 1, x, num);
// Tree[k].sum = Tree[2 * k].sum + Tree[2 * k + 1].sum;//递归过程中跟该每个节点的sum值
//}
//查询区间内的值和
long long int query(int k,int l,int r)//都是从根节点出=发搜索,k表示根节点
{
if (l <= Tree[k].l && Tree[k].r <= r)//查询区间覆盖了线段数所覆盖的区间
return Tree[k].sum;
int mid = (Tree[k].l + Tree[k].r) / 2;
Pushdown(k);//可能查询区间的父节点有懒标记,所以要向下调整
long long int sum = 0;
if (l <= mid)
sum += query(2 * k, l, r);
if (r > mid)
sum += query(2 * k + 1, l, r);
return sum;
}
int main()
{
scanf_s("%d%d", &N,&Q);
Tree = (Node*)malloc(sizeof(Node) * (N + 1)*4);
nums = (int*)malloc(sizeof(int) * (N + 1));
for (int i = 1; i <= N; i++)
scanf_s("%d", &nums[i]);
build(1, 1, N);//(根结点,维护区间[1,N])
while (Q--)
{
int chose = 0;
scanf_s("%d", &chose);
int l, r;
if (chose == 1)
{
int val;
scanf_s("%d%d%d", &l, &r, &val);
update(1, l, r, val);
}
else
{
scanf_s("%d%d", &l, &r);
printf("%lld\n", query(1, l, r));
}
}
return 0;
}
线段树的创建和使用
最新推荐文章于 2024-10-10 22:59:02 发布