题意:给一个数组,进行区间修改和求和操作。
线段树区间修改,直接放线段树咬,但是很多的细节需要注意。
千万不能upate(L,mid,2*k,val);update(mid+1,R,2*k+1,val).会改变目标区间的值。
比如n=10,修改区间(3,6)
1,左边:目标区间变为(3,5),树的区间为(1,5)
右边:目标区间变为(6,6)树的区间变为(6,10)
2, 左边:①左边:目标区间(3,3)树的区间(1,3)②右边:目标区间(4,5)树的区间(4,5)
(到目前为止都很正常,接下来右边的就不对了)
右边:①左边:目标区间(6,8)(这个时候就不对了,因为原来的目标区间是(3,6)而现在到了8了)。树的区间(6,8)
②右边:没有
#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
struct node
{
ll sum, lz, l, r;
};
node tree[MAXN<<2];
//建立线段树,没有坑,没有细节
void build(ll L, ll R, ll k)
{
tree[k].l = L;tree[k].r = R;
if (L == R)
{
scanf("%lld", &tree[k].sum);
tree[k].lz = 0;
return;
}
ll mid = (L + R) / 2;
build(L, mid, 2 * k);
build(mid + 1, R, 2 * k + 1);
tree[k].sum = tree[2 * k].sum + tree[2 * k + 1].sum;
}
//要加上父亲结点的lazy标记,左右区间的元素个数要数对
void pushdown(ll k)
{
if (tree[k].lz)
{
tree[2*k].lz+=tree[k].lz;
tree[2 * k + 1].lz += tree[k].lz;
ll mid = (tree[k].l + tree[k].r) / 2;
//左区间元素个数mid-tree[2*k].l+1
tree[2 * k].sum += (mid - tree[2 * k].l + 1) * tree[k].lz;
//右区间tree[2*k+1].r-mid
tree[2 * k + 1].sum += (tree[2 * k + 1].r - mid) * tree[k].lz;
tree[k].lz = 0;
}
}
void update(ll L, ll R, ll k, ll val)
{
if (tree[k].l >= L && tree[k].r <= R)
{
tree[k].sum += (tree[k].r - tree[k].l + 1) * val;
tree[k].lz += val;
return;
}
pushdown(k);
ll mid = (tree[k].l + tree[k].r) / 2;
//不能是upate(L,mid,2*k,val);update(mid+1,R,2*k+1,val)会出错
//看起来好像差不多,但是这样做,会使(L,R)改变
if (L <= mid)update(L, R, 2 * k, val);
if(R>mid) update(L, R, 2 * k + 1, val);
tree[k].sum = tree[2 * k].sum + tree[2 * k + 1].sum;
}
ll query(ll L, ll R, ll k)
{
if (tree[k].l >= L && tree[k].r <= R)
{
return tree[k].sum;
}
//记得pushdown,不然会少算很多
pushdown(k);
ll ans = 0, mid;
mid = (tree[k].l + tree[k].r) / 2;
if (L <= mid)ans += query(L, R, 2 * k);
if (R > mid)ans += query(L, R, 2 * k + 1);
return ans;
}
//debug的函数,查看每一个数字的值
/*void find(int k)
{
if (tree[k].l == tree[k].r)
{
printf("%lld ", tree[k].sum);
return;
}
pushdown(k);
int mid = (tree[k].l + tree[k].r) / 2;
find(2 * k);
find(2 * k + 1);
//printf("\n");
}*/
int main()
{
ll n, m, i, j;
char s[2];
while (scanf("%lld%lld", &n, &m) == 2)
{
build(1, n, 1);
ll t1, t2, t3,ans;
while (m--)
{
scanf("%s", s);
if (s[0] == 'Q')
{
scanf("%lld%lld", &t1, &t2);
ans = query(t1, t2, 1);
printf("%lld\n", ans);
}
else
{
scanf("%lld%lld%lld", &t1, &t2, &t3);
update(t1, t2, 1, t3);
}
}
//find(1);
}
return 0;
}