ACM: 线段树 poj 3468
2016-05-19 23:24
447 查看
A
Simple Problem with Integers
Description
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.
题意: 一组数组, 对它有两种操作, Q
A B: 访问区间[A,B]的数组累加和, C A B C: 区间[A,B]内每个
元素都加上C.
解题思路:
1.
经典的线段树题目, 只需在线段树每个节点上设置sum和add: 累加和,增量域. 题目迎刃而解.
2.
操作C时, 当满足当前区间[A,B]时, p->add =
p->add + C; 修改区间的增量即可.
当不满足时,
继续往左右区间改变增量之前要将当前的区间增量加入sum,
p->sum = p->sum +
(p->r - p->l + 1) *
p->add;
操作Q时,当满足当前区间[A,B]时,
记录结果result = p->sum +
(p->r - p->l +
1)*p->add;
当不满足时,
继续往左右区间查找之前要将当前的增量分配到左右子树区间上,
p->left->add
+= p->add;
p->right->add +=
p->add; p->add = 0; //最后记得清除.
p->sum += (p->r - p->l
+ 1)*p->add;
3. 最后, 要注意累加的结果会超出32位整型, 并且传入C增量时要用整型64位.
代码:
#include
<cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005
struct node
{
int l, r;
__int64 sum, add; //sum:区间和, add:区间的增量
}pt[MAX*4];
int n, m;
__int64 g[MAX];
__int64 a, b, c;
char ch[2];
__int64 result;
void buildTree(int
l, int r, int pos)
{
pt[pos].l = l, pt[pos].r = r;
pt[pos].add = 0;
if(l == r)
{
pt[pos].sum = g[l];
return ;
}
int mid = (pt[pos].l+pt[pos].r)/2;
buildTree(l, mid, pos*2);
buildTree(mid+1, r, pos*2+1);
pt[pos].sum =
pt[pos*2].sum+pt[pos*2+1].sum;
}
void add(int l, int
r, int pos, __int64 c)
{
if(pt[pos].l == l
&& pt[pos].r == r)
{
pt[pos].add += c;
return ;
}
int mid = (pt[pos].l+pt[pos].r)/2;
pt[pos].sum += (r-l+1)*c;
if(r <= mid)
add(l, r, pos*2, c);
else if(l > mid)
add(l, r, pos*2+1, c);
else
{
add(l, mid, pos*2, c);
add(mid+1, r, pos*2+1,
c);
}
}
void find(int l, int
r, int pos)
{
if(pt[pos].l == l
&& pt[pos].r == r)
{
result += (pt[pos].sum +
(r-l+1)*pt[pos].add);
return ;
}
int mid = (pt[pos].l+pt[pos].r)/2;
pt[pos].sum +=
(pt[pos].r-pt[pos].l+1)*pt[pos].add;
pt[pos*2].add += pt[pos].add;
pt[pos*2+1].add += pt[pos].add;
pt[pos].add = 0;
if(r <= mid)
find(l, r, pos*2);
else if(l > mid)
find(l, r, pos*2+1);
else
{
find(l, mid, pos*2);
find(mid+1, r, pos*2+1);
}
}
int main()
{
int i;
// freopen("input.txt","r",stdin);
while(scanf("%d %d",&n,
&m) != EOF)
{
for(i = 1; i <=
n; ++i)
scanf("%I64d",&g[i]);
buildTree(1, n, 1);
for(i = 1; i <=
m; ++i)
{
scanf("%s",ch);
if(ch[0] ==
'C')
{
scanf("%I64d
%I64d %I64d",&a, &b,
&c);
add(a,
b, 1, c);
}
else if(ch[0]
== 'Q')
{
scanf("%d
%d",&a, &b);
result
= 0;
find(a,
b, 1);
printf("%I64d\n",result);
}
}
}
return 0;
}
Simple Problem with Integers
Description
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.
题意: 一组数组, 对它有两种操作, Q
A B: 访问区间[A,B]的数组累加和, C A B C: 区间[A,B]内每个
元素都加上C.
解题思路:
1.
经典的线段树题目, 只需在线段树每个节点上设置sum和add: 累加和,增量域. 题目迎刃而解.
2.
操作C时, 当满足当前区间[A,B]时, p->add =
p->add + C; 修改区间的增量即可.
当不满足时,
继续往左右区间改变增量之前要将当前的区间增量加入sum,
p->sum = p->sum +
(p->r - p->l + 1) *
p->add;
操作Q时,当满足当前区间[A,B]时,
记录结果result = p->sum +
(p->r - p->l +
1)*p->add;
当不满足时,
继续往左右区间查找之前要将当前的增量分配到左右子树区间上,
p->left->add
+= p->add;
p->right->add +=
p->add; p->add = 0; //最后记得清除.
p->sum += (p->r - p->l
+ 1)*p->add;
3. 最后, 要注意累加的结果会超出32位整型, 并且传入C增量时要用整型64位.
代码:
#include
<cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005
struct node
{
int l, r;
__int64 sum, add; //sum:区间和, add:区间的增量
}pt[MAX*4];
int n, m;
__int64 g[MAX];
__int64 a, b, c;
char ch[2];
__int64 result;
void buildTree(int
l, int r, int pos)
{
pt[pos].l = l, pt[pos].r = r;
pt[pos].add = 0;
if(l == r)
{
pt[pos].sum = g[l];
return ;
}
int mid = (pt[pos].l+pt[pos].r)/2;
buildTree(l, mid, pos*2);
buildTree(mid+1, r, pos*2+1);
pt[pos].sum =
pt[pos*2].sum+pt[pos*2+1].sum;
}
void add(int l, int
r, int pos, __int64 c)
{
if(pt[pos].l == l
&& pt[pos].r == r)
{
pt[pos].add += c;
return ;
}
int mid = (pt[pos].l+pt[pos].r)/2;
pt[pos].sum += (r-l+1)*c;
if(r <= mid)
add(l, r, pos*2, c);
else if(l > mid)
add(l, r, pos*2+1, c);
else
{
add(l, mid, pos*2, c);
add(mid+1, r, pos*2+1,
c);
}
}
void find(int l, int
r, int pos)
{
if(pt[pos].l == l
&& pt[pos].r == r)
{
result += (pt[pos].sum +
(r-l+1)*pt[pos].add);
return ;
}
int mid = (pt[pos].l+pt[pos].r)/2;
pt[pos].sum +=
(pt[pos].r-pt[pos].l+1)*pt[pos].add;
pt[pos*2].add += pt[pos].add;
pt[pos*2+1].add += pt[pos].add;
pt[pos].add = 0;
if(r <= mid)
find(l, r, pos*2);
else if(l > mid)
find(l, r, pos*2+1);
else
{
find(l, mid, pos*2);
find(mid+1, r, pos*2+1);
}
}
int main()
{
int i;
// freopen("input.txt","r",stdin);
while(scanf("%d %d",&n,
&m) != EOF)
{
for(i = 1; i <=
n; ++i)
scanf("%I64d",&g[i]);
buildTree(1, n, 1);
for(i = 1; i <=
m; ++i)
{
scanf("%s",ch);
if(ch[0] ==
'C')
{
scanf("%I64d
%I64d %I64d",&a, &b,
&c);
add(a,
b, 1, c);
}
else if(ch[0]
== 'Q')
{
scanf("%d
%d",&a, &b);
result
= 0;
find(a,
b, 1);
printf("%I64d\n",result);
}
}
}
return 0;
}
相关文章推荐
- ACM: 线段树 poj 2886 约瑟夫问题
- ACM: 线段树 poj 2777 继续熟练线…
- 协同开发时, 如何合并不稳定的联调代码?
- ACM: 线段树 poj 2828 认真对待每…
- ACM: trie树 poj 2513
- 计算机和资料 转载
- 凌宇的项目之旅-关于自定义锁屏
- Jmeter文章索引贴
- codeforces 675C C. Money Transfers(贪心)
- ACM: 线段树 poj 1177
- ACM: 线段树 poj 1151 足足想了三…
- ACM: 线段树 poj 2352
- ACM: 最小堆 poj 2274 思路清晰, …
- ACM: 最小堆 poj 2227 最小堆 fro…
- ACM: 划分树 poj 2761 在poj2104基…
- ACM: 动态规划题 poj 1036 问题简…
- ACM: 动态规划题 poj 2033 (博客好…
- 包装类
- ARM (三) arm中C/C++及汇编语言的…
- ARM (二) arm指令分类及其寻址方式