转载请注明出处:http://blog.csdn.net/u012860063

Description

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

Hint

The sums may exceed the range of 32-bit integers.

Source

代码例如以下:

//线段树功能:update:成段增减 query:区间求和
//此题为Poj 3468 代码 #include <cstdio>
#include <algorithm>
using namespace std;
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
//lson和rson分辨表示结点的左儿子和右儿子
//rt表示当前子树的根(root),也就是当前所在的结点
#define LL long long
const int maxn = 111111;
//maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
LL add[maxn<<2];//用来标记每一个节点,为0则表示没有标记,否则为标记。
LL sum[maxn<<2];//求和
void PushUp(int rt) //把当前结点的信息更新到父结点
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void PushDown(int rt,int len)//把当前结点的信息更新给儿子结点,len为分区间长度
{//对某一个区间进行改变,假设被标记了,在查询的时候就得把改变传给子节点,由于查询的并不一定是当前区间
if (add[rt]) //已经标记过。该区间被改变过
{
//由于rt的儿子节点可能被多次延迟标记。而且rt的儿子节点的延迟标记没有向rt的孙子节点移动,所以用“+=”
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
/*此处用add[rt]乘以区间长度,不是add[rt<<1], 由于rt的儿子节点假设被多次标记,之前被标记时,
就已经对sum[rt<<1]更新过了。 */
sum[rt<<1] += add[rt] * (len - (len >> 1));//更新左儿子的和
sum[rt<<1|1] += add[rt] * (len >> 1);//更新右儿子的和
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);
PushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if (L <= l && r <= R)
{
add[rt] += c;
sum[rt] += (LL)c * (r - l + 1);//更新代表某个区间的节点和,该节点不一定是叶子节点
return ;
}
/*当要对被延迟标记过的这段区间的儿子节点进行更新时,先要将延迟标记向儿子节点移动
当然,假设一直没有对该段的儿子节点更新,延迟标记就不须要向儿子节点移动,这样就使
更新操作的时间复杂度仍为O(logn),也是使用延迟标记的原因。
*/
PushDown(rt , r - l + 1);//向下传递
int mid = (l + r) >> 1;
if (L <= mid)
update(L , R , c , lson);//更新左儿子
if (mid < R)
update(L , R , c , rson);//更新右儿子
PushUp(rt);//向上传递更新和
}
LL query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return sum[rt];
}//要取rt子节点的值时。也要先把rt的延迟标记向下移动
PushDown(rt , r - l + 1);
int mid = (l + r) >> 1;
LL ret = 0;
if (L <= mid)
ret += query(L , R , lson);
if (mid < R)
ret += query(L , R , rson);
return ret;
}
int main()
{
int N , Q;
scanf("%d%d",&N,&Q);//N为节点数
build(1 , N , 1); //建树
while (Q--)//Q为询问次数
{
char op[2];
int a , b , c;
scanf("%s",op);
if (op[0] == 'Q')
{
scanf("%d%d",&a,&b);
printf("%lld\n",query(a , b , 1 , N , 1));
}
else
{
scanf("%d%d%d",&a,&b,&c);//c为区间a到b添加的值
update(a , b , c , 1 , N , 1);
}
}
return 0;
}

最新文章

  1. webpack模块加载css文件及图片地址
  2. TortoiseSVN与VisualSVN Server搭建SVN版本控制系统
  3. 关于aggregation 语法和表达式大全(最新3.4版)
  4. Python图片处理
  5. PerconaXtraBackup 压缩备份集
  6. Windows Azure Web Site (14) Azure Web Site IP白名单
  7. 【温故而知新-Javascript】使用 DOM 元素
  8. java正则API简单解析
  9. MongoDB用户管理
  10. TCP/IP,HTTP,Socket的区别与联系
  11. UVALive 7464 Robots (贪心)
  12. Test Bench基础知识笔记
  13. 【转】Ubuntu Linux 下文件名乱码(无效的编码)的快速解决办法
  14. hibernate持久化框架
  15. Elasticsearch就这么简单
  16. python之内置函数(一)
  17. angular.js 渲染
  18. api接口简短实力
  19. 【转】mysql给root开启远程访问权限,修改root密码
  20. java链接JDBC中的?问题

热门文章

  1. Delphi控件下载网
  2. WCF技术剖析之十六:数据契约的等效性和版本控制
  3. nest expression &amp;amp; Pyparsing
  4. 单选按钮易忽略的Group属性
  5. Linux - VIM(VI)编辑器
  6. Eclipse使用总结
  7. SuperSocket应用之FTP源码解析
  8. linux kill进程和子进程小trick
  9. 微信JS-SDK说明文档
  10. ViEmu For VS2010 3.0 解除30天限制的方法