题目描述

You have N integers, A1, A2, ... , 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 A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.

Each of the next Q lines represents an operation.

"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.

"Q a b" means querying the sum of Aa, Aa+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.

解题思路

不同于改段求点或改点求段,这是一个改段求段的题目

有两种方法接题:

第一种为利用树状数组:

区间更新这里引进了一个数组delta数组,delta[i]表示区间 [i, n] 的共同增量,每次你需要更新的时候只需要更新delta数组就行了,因为每段区间更新的数都记录在这个数组

中,那怎么查询前缀和呐?

sum[i]=a[1]+a[2]+a[3]+......+a[i]+delta[1](i-0)+delta[2](i-1)+delta[3](i-2)+......+delta[i](i-i+1);

= sigma( a[x] ) + sigma( delta[x] * (i + 1 - x) )

= sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )

(引用自吕程博客)

具体代码为

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int M=100010;
long long add_sum[M];
long long add[M];
long long ori[M];
int MN;
int Q;
int lowbit(int x)
{
return x&(-x);
}
void update(int i,int v,long long* a)
{
for(;i<=MN;i+=lowbit(i)){
a[i]+=v;
}
}
long long getsum(int r,long long *a)
{
long long resr=0;
for(;r>0;r-=lowbit(r)){
resr+=a[r];
}
return resr;
}
int main()
{
//freopen("data.in","r",stdin);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int tem;
int l,r,val;
while(cin>>MN>>Q){
memset(ori,0,sizeof(ori));
memset(add_sum,0,sizeof(add_sum));
memset(add,0,sizeof(add));
for(int i=1;i<=MN;i++){
cin>>tem;
update(i,tem,ori);
}
string ch;
for(int i=0;i<Q;i++){
cin>>ch;
if(ch=="Q"){
cin>>l>>r;
cout<<getsum(r,ori)-getsum(l-1,ori)-l*getsum(l-1,add)+(r+1)*getsum(r,add)-getsum(r,add_sum)+getsum(l-1,add_sum)<<endl;
}
if(ch=="C"){
cin>>l>>r>>val;
update(l,val,add);
update(r+1,-val,add);
update(l,val*(l),add_sum);
update(r+1,-val*(r+1),add_sum);
}
}
}
}

注意:add_sum数组保存的是add[i]*i之后的值





第二种方法为利用线段树

可以写一个利用结构体实现的线段树,然后加懒标。我地AC代码是按照刘汝佳的板写的,我觉得他地方法比较简洁,更好玩

下面是代码(详解见算法竞赛入门经典-训练指南):

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
const int M = 4*100010;
long long sumv[M];//线段树sum数组
long long add[M];
long long x, y;//全局变量,update与query时使用
long long addval;
long long _sum;
//*********************//
void update(int id, int l, int r)
{
long long m = l + (r - l) / 2;
if (x <= l&&y >= r){
add[id] += addval;
}
else{
if (x <= m) update(2 * id, l, m);
if (y>m) update(2 * id + 1, m+1, r);
}
sumv[id]=0;//!!!!!!!!!注意此步骤
if (l<r){
sumv[id] = sumv[2 * id] + sumv[2 * id + 1];
}
sumv[id] += add[id] * (r - l + 1);
}
void query(int id, int l, int r, long long addv)
{
long long m = l + (r - l) / 2;
if (x <= l&&y >= r){
_sum += sumv[id] + addv*(r - l + 1);
}
else{
//addv += add[id];
if (x <= m){
query(2 * id, l, m, addv+add[id]);
}
if (y>m) query(2 * id + 1, m+1, r, addv+add[id]);
}
}
int main()
{
//freopen("data.in", "r", stdin);
//freopen("data.out","w",stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
long long n, q;
while (cin >> n >> q){
memset(sumv, 0, sizeof(sumv));
memset(add, 0, sizeof(add));
for (int i = 1; i <= n; i++){
cin >> addval;
x = i;
y = i;
update(1, 1, n);
}
string ch;
for (int i = 0; i<q; i++){
cin >> ch;
if (ch == "Q"){
_sum = 0;
cin >> x >> y;
query(1, 1, n, 0);
cout << _sum << endl;
}
if (ch == "C"){
cin >> x >> y >> addval;
update(1, 1, n); }
}
}
}

POJ3468--A Simple Problem with Integers--线段树/树状数组 改段求段的更多相关文章

  1. poj3468 A Simple Problem with Integers (线段树区间最大值)

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

  2. POJ3468 A Simple Problem with Integers(线段树延时标记)

    题目地址http://poj.org/problem?id=3468 题目大意很简单,有两个操作,一个 Q a, b 查询区间[a, b]的和 C a, b, c让区间[a, b] 的每一个数+c 第 ...

  3. poj3468 A Simple Problem with Integers(线段树模板 功能:区间增减,区间求和)

    转载请注明出处:http://blog.csdn.net/u012860063 Description You have N integers, A1, A2, ... , AN. You need ...

  4. POJ3468 A Simple Problem with Integers —— 线段树 区间修改

    题目链接:https://vjudge.net/problem/POJ-3468 You have N integers, A1, A2, ... , AN. You need to deal wit ...

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

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

  6. 2018 ACMICPC上海大都会赛重现赛 H - A Simple Problem with Integers (线段树,循环节)

    2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 H - A Simple Problem with Integers (线段树,循环节) 链接:https://ac.nowcoder.co ...

  7. POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)

    A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...

  8. POJ3648 A Simple Problem with Integers(线段树之成段更新。入门题)

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

  9. poj 3468 A Simple Problem with Integers 线段树第一次 + 讲解

    A Simple Problem with Integers Description You have N integers, A1, A2, ... , AN. You need to deal w ...

  10. Poj 3468-A Simple Problem with Integers 线段树,树状数组

    题目:http://poj.org/problem?id=3468   A Simple Problem with Integers Time Limit: 5000MS   Memory Limit ...

随机推荐

  1. chapter 13_4 跟踪table的访问

    __index和__newindex都是在table中没有所需访问的index时才发挥作用. 因此,只有将一个table保持为空,才有可能捕捉到所有对它的访问.为了监视一个table的所有访问,就应该 ...

  2. redis数据类型:lists

    redis的list类型其实就是一个每个子元素都是string类型的双向链表. 我们可以通过push,pop操作从链表的头部或者尾部添加删除元素,这样list即可以作为 栈,又可以作为队列. lpus ...

  3. linux之ls -l|grep "^-"|wc -l命令

    查看某文件夹下文件的个数 ls -l |grep "^-"|wc -l 或 find ./company -type f | wc -l 查看某文件夹下文件的个数,包括子文件夹里的 ...

  4. 解决Eclipse无法添加Tomcat服务器的问题

    eclipse配置好以后,如果Tomcat服务器在文件系统的位置发生了变化,则需要重新配置Tomcat服务器,这时会遇到无法设置服务器的问题 即图中框起来的部分无法进行操作,这时需要 关闭Eclips ...

  5. html5--基础笔记

    1.对于<a>标签 以前: <h2><a href="index.html">The home page</a></h2> ...

  6. 《JavaScript高级程序设计》读书笔记 ---操作符二

    关系操作符 小于(<).大于(>).小于等于(<=)和大于等于(>=)这几个关系操作符用于对两个值进行比较,比较的规则与我们在数学课上所学的一样.这几个操作符都返回一个布尔值, ...

  7. JavaScript中以构造函数的方式调用函数

    转自:http://www.cnblogs.com/Saints/p/6012188.html 构造器函数(Constructor functions)的定义和任何其它函数一样,我们可以使用函数声明. ...

  8. HTTP 返回状态值详解

    当用户点击或搜索引擎向网站服务器发出浏览请求时,服务器将返回Http Header Http头信息状态码,常见几种如下: 1.Http/1.1 200 OK 访问正常  表示成功访问,为网站可正常访问 ...

  9. 多选出差同事id,拼接,去掉最后逗号

    ===========方法1 substr() ,永远都是.(第一个参数)开始位置.(第二个参数)截取个数 ,负数表示都后面开始数 substr($data['members'],0,strlen($ ...

  10. jquery多级下拉菜单

    var menu = new Click('#menu',{target:'p',parent:'li',contr:'ul',way:0}); /* 参数说明: target : 点击事件发生在该元 ...