You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

题意:

  • [1,n]区间每个点有初始值,C(x,y,z)操作再[x,y]区间每个点加值z; Q(x,y)询问[x,y]区间的和。

思路:

  • 显然,线段树+lazy可以很好地解决区间修改问题。

那么问题来了:

  • 如果非要用树状数组呢?当然可以对修改区间[x,y]的没一个点进行操作,但是一次修改的复杂度就是长度L*lgn,显然是不行的。

我们从前缀和的思路来解决这个问题,我们以前都用过差分来记录前缀和,然后O(1)地得到区间和:

例如,[L,R]区间+x ,则sum[L]+=x;  xum[R+1]-=x;最后sum[i]+=sum[i-1];就可以做差得到区间和了。

但是这里有修改操作,每次询问都sum[i]+=sum[i-1]累加一次肯定是不行的,正确方法如下。

  • STEP1:更新操作:把[l,r]所有的数加上x,可以看做把[l,n]所有数加上x,再把[r+1,n]所有数 减去d。那我们引入一个新的数组delta[n],delta[i]记录了       [i,n]每个数的增量。操作就转化为了 delta[l]+=x,delta[r+1]-=x;
  • STEP2:查询操作:求[l,r]的和,当然是看做求sum[1,r]-sum[1,l-1]啦。就是求sum(x)。 首先,要加上原数组的基数前缀和origin[x],这个一开始就能求出来:   sum[x]=origin[x]=Σa[i];
  • STEP3,考虑delta数组,delta[1]为[1,x]贡献了x个delta[1],delta[2]为[2,x]贡献了x-1个delta[2], 以此类推,delta[i]贡献了(x+1-i)个delta[i]。那么               sum[x]=origin[x]+delta[1]*x+delta[2]*(x-1)+...delta[x] = origin[x]+(x+1)*Σdelta[i]-Σ(i*delta[i]);

这样就转化为了三个树状数组:orgin可以预处理得到,后面两个可以单点更新得到。

对比:

虽然总的来说,线段树能实现的东西比树状数组多。但是能用树状数组解决的方案一般会再空间时间代码量上优于线段树,而且不容易写错,不要问我为什么知道,QwQ。而且二维树状数组也很好写,而线段树。。。。

线段树代码:

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn=;
int n,m;int a[maxn];
struct TREE
{
ll sum[maxn<<];int lazy[maxn<<];
void build(int Now,int l,int r)
{
lazy[Now]=;
if(l==r) { sum[Now]=a[l]; return;}
int Mid=(l+r)>>;
build(Now<<,l,Mid);
build(Now<<|,Mid+,r);
pushup(Now);
}
void add(int Now,int l,int r,int x,int y,int val)
{
if(x<=l&&y>=r) { sum[Now]+=(ll)(r-l+)*val;lazy[Now]+=val; return ;}
pushdown(Now,l,r); int Mid=(l+r)>>;
if(y<=Mid) add(Now<<,l,Mid,x,y,val);
else if(x>Mid) add(Now<<|,Mid+,r,x,y,val);
else add(Now<<,l,Mid,x,Mid,val),add(Now<<|,Mid+,r,Mid+,y,val);
pushup(Now);
}
ll query(int Now,int l,int r,int x,int y)
{
if(x<=l&&y>=r) return sum[Now];
pushdown(Now,l,r); int Mid=(l+r)>>;
if(y<=Mid) return query(Now<<,l,Mid,x,y);
else if(x>Mid) return query(Now<<|,Mid+,r,x,y);
else return query(Now<<,l,Mid,x,Mid)+query(Now<<|,Mid+,r,Mid+,y);
pushup(Now);
}
void pushup(int Now) { sum[Now]=sum[Now<<]+sum[Now<<|];}
void pushdown(int Now,int l,int r)
{
int Mid=(l+r)>>;
lazy[Now<<]+=lazy[Now];sum[Now<<]+=(ll)(Mid-l+)*lazy[Now];
lazy[Now<<|]+=lazy[Now];sum[Now<<|]+=(ll)(r-Mid)*lazy[Now];
lazy[Now]=;
}
}Tree;
int main()
{
while(~scanf("%d%d",&n,&m)){
for(int i=;i<=n;i++) scanf("%d",&a[i]);
Tree.build(,,n);
for(int i=;i<=m;i++){
char opt[];int x,y,z;
scanf("%s",opt);
if(opt[]=='Q') scanf("%d%d",&x,&y),printf("%lld\n",Tree.query(,,n,x,y));
else scanf("%d%d%d",&x,&y,&z),Tree.add(,,n,x,y,z);
}
} return ;
}

树状数组代码:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
ll a[maxn],b[maxn],c[maxn];
char opt[];int n,m;
int lowbit(int x) {return x&(-x);}
void add(int x,int val)
{
for(int i=x;i<=n+;i+=lowbit(i))
b[i]+=val,c[i]+=x*val;
}
ll query(int x)
{
ll res=a[x];
for(int i=x;i;i-=lowbit(i)) res+=b[i]*(x+);
for(int i=x;i;i-=lowbit(i)) res-=c[i];
return res;
}
int main()
{
while(~scanf("%d%d",&n,&m)){
for(int i=;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-];
for(int i=;i<=n;i++) b[i]=c[i]=;
while(m--){
scanf("%s",opt); int x,y,z;
if(opt[]=='Q')scanf("%d%d",&x,&y),printf("%lld\n",query(y)-query(x-));
else scanf("%d%d%d",&x,&y,&z),add(x,z),add(y+,-z);
}
} return ;
}

POJ3468 A Simple Problem with Integers(数状数组||区间修改的RMQ问题)的更多相关文章

  1. POJ3468 A Simple Problem With Integers 树状数组 区间更新区间询问

    今天学了很多关于树状数组的技巧.一个是利用树状数组可以简单的实现段更新,点询问(二维的段更新点询问也可以),每次修改只需要修改2个角或者4个角就可以了,另外一个技巧就是这题,原本用线段树做,现在可以用 ...

  2. 线段树---poj3468 A Simple Problem with Integers:成段增减:区间求和

    poj3468 A Simple Problem with Integers 题意:O(-1) 思路:O(-1) 线段树功能:update:成段增减 query:区间求和 Sample Input 1 ...

  3. A Simple Problem with Integers(树状数组HDU4267)

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (J ...

  4. POJ3468 A Simple Problem with Interger [树状数组,差分]

    题目传送门 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 1 ...

  5. poj 3468 A Simple Problem with Integers【线段树区间修改】

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 79137   ...

  6. 题解报告:poj 3468 A Simple Problem with Integers(线段树区间修改+lazy懒标记or树状数组)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  7. HDU 4267 A Simple Problem with Integers --树状数组

    题意:给一个序列,操作1:给区间[a,b]中(i-a)%k==0的位置 i 的值都加上val  操作2:查询 i 位置的值 解法:树状数组记录更新值. 由 (i-a)%k == 0 得知 i%k == ...

  8. poj3468 A Simple Problem with Integers(线段树区间更新)

    https://vjudge.net/problem/POJ-3468 线段树区间更新(lazy数组)模板题 #include<iostream> #include<cstdio&g ...

  9. POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

随机推荐

  1. MySql(四):备份与恢复

    一.数据库备份使用场景 下面我就列举一下我个人理解的我们能够需要用到数据库备份的一些比较常见的情况吧. a.数据丢失应用场景 1.人为操作失误造成某些数据被误操作:2.软件BUG 造成数据部分或者全部 ...

  2. Ajax请求的跨域(CORS)问题

    用浏览器,通过XHR(XMLHttpRequest)请求向另外一个域名请求数据时.会碰到跨域(CORS)问题. CORS:Cross-Origin Resource Sharing 什么是跨域? 简单 ...

  3. python学习(七)字典学习

    #!/usr/bin/python # 字典 # 当时学java的时候, 语言基础就学了好久, 然后是各种API, 最后才是集合 # 键值对, 可变 # 1. 映射操作 D = {'food' : ' ...

  4. PeekMessage究竟做了什么?

    1.UI线程 2.工作线程 把Delphi里TThread的WaitFor函数转化成C++代码,就会是下面这个样子. BOOL TThread::WaitFor(HANDLE hThread) { M ...

  5. Android开发:LocationManager获取经纬度及定位过程(附demo)

    在Android开发其中.常常须要用到定位功能,尤其是依赖于地理位置功能的应用.非常多人喜欢使用百度地图,高德地图提供的sdk.开放API,可是在只须要经纬度,或者城市,街道地址等信息.并不须要提供预 ...

  6. 【BZOJ4453】cys就是要拿英魂! 后缀数组+单调栈+set

    [BZOJ4453]cys就是要拿英魂! Description pps又开始dota视频直播了!一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下来,每个技能用一个 ...

  7. WebApi基础

    1:当Controller中有相同参数的方法时,请求调用会报错 [HttpGet] public IEnumerable<string> Resturn() { return new st ...

  8. MySQL——函数

    MySQL数据库提供了很多函数包括: (1)数学函数 (2)字符串函数 (3)日期和时间函数 (4)条件判断函数 (5)系统信息函数 (6)加密函数 (7)格式化函数 一.数学函数 数学函数主要用于处 ...

  9. Allegro PCB中添加汉字

    注明出处:http://www.cnblogs.com/einstein-2014731/p/5650943.html Cadence用起来比AltiumDesigner要麻烦些,但是也更开放,更灵活 ...

  10. css浏览器兼容问题集锦

    表单按钮用input type=submit和a链接两者表现不一致的问题 表单的输入框.文本.验证码图片没有对齐 IE6/7中margin失效 IE6中margin双边距 1.问题: 表单按钮用inp ...