版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Triple_WDF/article/details/81200346
题意:有一系列的数字,然后对某个区间进行更新,C a b c,表示将区间[a, b]中的所有数字加上c,Q a b,表示查询区间[a, b]之间所有数字的和。
想法:由于这系列数字是10w个,操作10w次,所有说暴力是显然不优秀的,所以很容易想到用线段树去维护这10w个数据,然后采用区间更新的方式来进行操作,区间更新的关键就是弄清楚lazy的含义:对线段树上该节点所代表的范围的内的所有的点进行一致的操作,这里也就是加法操作。只有在需要该节点的子节点之后,才将lazy积攒下来的数值进行下方,这样的话避免了每次区间更新都要进行区间内每一个点的点更新那样,非常的浪费时间。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define L(x) x << 1
#define R(x) (x << 1) | 1
using namespace std;
const int max_node = 100005;
int N, Q;
class CSegment_Tree
{
public:
CSegment_Tree(int node_num/*维护数组元素个数*/);
~CSegment_Tree()
{
delete[] segtree;
}
void PushDown(int cur_tnode/*线段树当前节点序号*/);
void PushUp(int cur_tnode);
void Build(int cur_tnode, int lft/*维护区间-左*/, int rht/*维护区间-右*/);
void Updata(int cur_tnode, int pos_lft/*更新区间-左*/, int pos_rht/*更新区间-右*/, long long int val/*区间更新要增加的权值*/);
long long int Query(int cur_tnode, int pos_lft/*访问区间-左*/, int pos_rht/*访问区间-右*/);
private:
struct Tree_node
{
int seg_lft, seg_rht;
long long int lazy;
long long int val;
int mid()
{
return (seg_lft + seg_rht) >> 1;
}
};
struct Tree_node *segtree;
};
CSegment_Tree::CSegment_Tree(int num_node)
{
struct Tree_node *temp = new Tree_node[num_node * 4];
segtree = temp;
temp = NULL;
delete[] temp;
}
void CSegment_Tree::PushDown(int cur_tnode)
{
/*
函数目的:lazy表示,当前这个节点所代表的区间中的所有的点都要进行lazy值得相关操作
是具有统一性的一次操作,不限于只是加减,比大小
*/
if(segtree[cur_tnode].lazy)
{
segtree[L(cur_tnode)].lazy += segtree[cur_tnode].lazy;
segtree[L(cur_tnode)].val += (segtree[L(cur_tnode)].seg_rht - segtree[L(cur_tnode)].seg_lft + 1) * segtree[cur_tnode].lazy;
segtree[R(cur_tnode)].lazy += segtree[cur_tnode].lazy;
segtree[R(cur_tnode)].val += (segtree[R(cur_tnode)].seg_rht - segtree[R(cur_tnode)].seg_lft + 1) * segtree[cur_tnode].lazy;
segtree[cur_tnode].lazy = 0;
}
}
void CSegment_Tree::PushUp(int cur_tnode)
{
/*
pushup操作是为了更新完区间之后,对代表该区间的若干节点的父亲,祖宗进行更新
*/
segtree[cur_tnode].val = segtree[L(cur_tnode)].val + segtree[R(cur_tnode)].val;
}
void CSegment_Tree::Build(int cur_tnode, int lft, int rht)
{
segtree[cur_tnode].seg_lft = lft;
segtree[cur_tnode].seg_rht = rht;
segtree[cur_tnode].val = 0;
segtree[cur_tnode].lazy = 0;
if(lft != rht)
{
int mid = segtree[cur_tnode].mid();
Build(L(cur_tnode), lft, mid);
Build(R(cur_tnode), mid + 1, rht);
}
}
void CSegment_Tree::Updata(int cur_tnode, int pos_lft, int pos_rht, long long int val)
{
int lft = segtree[cur_tnode].seg_lft;
int rht = segtree[cur_tnode].seg_rht;
if(pos_lft <= lft && rht <= pos_rht)
{
segtree[cur_tnode].lazy += val;
segtree[cur_tnode].val += (rht - lft + 1) * val;
}
else
{
PushDown(cur_tnode);
int mid = segtree[cur_tnode].mid();
if(pos_lft <= mid) Updata(L(cur_tnode), pos_lft, pos_rht, val);
if(pos_rht > mid) Updata(R(cur_tnode), pos_lft, pos_rht, val);
PushUp(cur_tnode);
}
}
long long int CSegment_Tree::Query(int cur_tnode, int pos_lft, int pos_rht)
{
int lft = segtree[cur_tnode].seg_lft;
int rht = segtree[cur_tnode].seg_rht;
if(pos_lft <= lft && rht <= pos_rht)
{
return segtree[cur_tnode].val;
}
else
{
PushDown(cur_tnode);
int mid = segtree[cur_tnode].mid();
long long int res1 = 0;
long long int res2 = 0;
if(pos_lft <= mid) res1 = Query(L(cur_tnode), pos_lft, pos_rht);
if(pos_rht > mid) res2 = Query(R(cur_tnode), pos_lft, pos_rht);
return res1 + res2;
}
}
int main ()
{
while(~scanf("%d%d", &N, &Q))
{
CSegment_Tree nsegtree(N + 1);
nsegtree.Build(1, 1, N);
for(int i = 1; i <= N; i++)
{
long long int in_x;
scanf("%lld", &in_x);
nsegtree.Updata(1, i, i, in_x);
}
for(int i = 1; i <= Q; i++)
{
char ways[2];
scanf("%s", ways);
if(ways[0] == 'Q')
{
int x, y;
scanf("%d%d", &x, &y);
printf("%lld\n", nsegtree.Query(1, x, y));
}
else
{
int x, y;
long long int c;
scanf("%d%d%lld", &x, &y, &c);
nsegtree.Updata(1, x, y, c);
}
}
}
return 0;
}