线段树。
不过这次是对于整段更新操作的树,比起前面的单点更新略复杂,但对线段树的掌握要求更为全面。
这里的整段更新时用到了一个add域,来存储增量。在每次更新的随着update操作递归深入的层次由上层结点对下层结点进行更新操作,而不是一次性将所有的结点都更新。(一次性全部更新的时间复杂度是O(nlogn),而不用树形结构时的更新操作时间复杂度仅为O(n),体现不出线段树的优势)。这个操作成为延时操作。大大降低了时间复杂度。
思路:如果每次更新都更新到底,会TLE(可以尝试一下)归属于区间更新 当更新某一段时,记录其状态,不再往下更新,直到下次更新或查询它的子结点时,再往下更新。
#include<cstdio>
using namespace std;
typedef struct
{
int l,r;
__int64 value,add;
} node;
const int Maxsize = 100010;
int data[Maxsize];
__int64 ans;
node tree[4*Maxsize];
void pushup(int v)/*自底向上更新*//*向上回溯*/
{
tree[v].value = tree[v<<1].value + tree[v<<1|1].value;
return;
}
void pushdown(int v)/*由上自下更新,主要是更新add产生的数据更新*//*延时更新*/
{
tree[v<<1].add += tree[v].add;
tree[v<<1].value += (tree[v<<1].r - tree[v<<1].l + 1)*tree[v].add;
tree[v<<1|1].add += tree[v].add;
tree[v<<1|1].value += (tree[v<<1|1].r - tree[v<<1|1].l + 1)*tree[v].add;
tree[v].add = 0;/*add值传递完后清零*/
}
int main()
{
void build(int v,int l,int r);
void update(int v,int l,int r,int m);
void query(int v,int l,int r);
int n,m;
while(~scanf("%d %d",&n,&m))
{
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&data[i]);
}
build(1,1,n);
char str[2];
int a,b,c;
for(int i = 0 ; i < m ; i++)
{
scanf("%s",str);
if(str[0] == 'Q')
{
scanf("%d %d",&a,&b);
ans = 0LL;
query(1,a,b);
printf("%I64d\n",ans);
}
else if(str[0] == 'C')
{
scanf("%d %d %d",&a,&b,&c);
update(1,a,b,c);
}
}
}
return 0;
}
void build(int v,int l,int r)/*建树*/
{
tree[v].l = l;
tree[v].r = r;
tree[v].add = 0;
if(l == r)
{
tree[v].value = data[r];
return;
}
int mid = (l+r)>>1;
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
pushup(v);
}
void update(int v,int l,int r,int m)/*更新*/
{
if(tree[v].r == r && tree[v].l == l)
{
tree[v].value +=m*(r-l+1);
tree[v].add += m;
return;
}
tree[v].value += (r-l+1)*m;/*不是add增量所增加的完整区间,但是它的大范围区间的值也要改变,加上其增量*/
if(tree[v].add)/*由父节点的add值来向子节点的value值做更改*//*延时更新*/
{
pushdown(v);
}
int mid = (tree[v].l + tree[v].r)>>1;
if(r <= mid)
{
update(v<<1,l,r,m);
}
else
{
if(l > mid)
{
update(v<<1|1,l,r,m);
}
else
{
update(v<<1,l,mid,m);
update(v<<1|1,mid+1,r,m);
}
}
}
void query(int v,int l,int r)/*查询*/
{
if(tree[v].l == l && tree[v].r == r)
{
ans+=tree[v].value;
return;
}
if(tree[v].add)
{
pushdown(v);
}
int mid = (tree[v].r+tree[v].l)>>1;
if(r <= mid)
{
query(v<<1,l,r);
}
else
{
if(l > mid)
{
query(v<<1|1,l,r);
}
else
{
query(v<<1,l,mid);
query(v<<1|1,mid+1,r);
}
}
}