POJ-3468
A Simple Problem with Integers
这道题线段树模板题,线段树区间求和区间修改
题目多次询问,遇到C修改区间,遇到Q求和
lay-tag方法
sum[]数组记录区间和
add[]记录结点是否用到tag原理。向下更新的时候重新将值置0.
同样记得向上更新
lazy-tag原理是当修改的是一整块区间时,只对这个线段区间进行整体修改,内部的每个元素先不做修改,只有当这部分线段的一致性被破坏时,才传递修改子区间。例如一个区间包含线段区间的一部分时。处于交错状态时需要传递修改子区间。
实现代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
ll sum[N << 2], add[N << 2];
int n, m;
void push_up(int rt)//向上更新
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void push_down(int rt, int m)//更新子结点
{
if (add[rt])
{
add[rt << 1] += add[rt];
add[rt << 1 | 1] += add[rt];
sum[rt << 1] += (m - (m >> 1)) * add[rt];
sum[rt << 1 | 1] += (m >> 1) * add[rt];
add[rt] = 0;//取消本层标记
}
}
void build(int l, int r, int rt)
{
add[rt] = 0;
if (l == r)
{
scanf ("%lld", &sum[rt]);
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
push_up(rt);
}
void update(int a, int b, ll c, int l, int r, int rt)
{
if (a <= l && b >= r)
{
sum[rt] += (r - l + 1) * c;
add[rt] += c;
return ;
}
push_down(rt, r - l + 1);//向下更新
int mid = (l + r) >> 1;
if (a <= mid)//分成两半继续深入
{
update(a, b, c, lson);
}
if (b > mid)
{
update(a, b, c, rson);
}
push_up(rt);//向上更新
}
ll query(int a, int b, int l, int r, int rt)
{
if (a <= l && b >= r)
{
return sum[rt];
}
push_down(rt, r - l + 1);
int mid = (r + l) >> 1;
ll ans = 0;
if (a <= mid)
{
ans += query(a, b, lson);
}
if (b > mid)
{
ans += query(a, b, rson);
}
return ans;
}
int main()
{
cin >> n >> m;
build(1, n, 1);
while (m--)
{
char str[2];
int a, b;
ll c;
scanf ("%s", str);
if (str[0] == 'C')
{
scanf ("%d%d%lld", &a, &b, &c);
update(a, b, c, 1, n, 1);
}
else
{
scanf ("%d%d", &a, &b);
cout << query(a, b, 1, n, 1) << endl;
}
}
return 0;
}