码迷,mamicode.com
首页 > 其他好文 > 详细

POJ3468 A Simple Problem with Integers

时间:2016-09-12 22:11:31      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

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.

Source

 
 
 
正解:树状数组(区间修改、区间查询)
解题报告:
  裸题。参考博客:http://blog.csdn.net/longshuai0821/article/details/7855519
   首先,看更新操作update(s, t, d)把区间A[s]...A[t]都增加d,我们引入一个数组delta[i],表示A[i]...A[n]的共同增量,n是数组的大小。那么update操作可以转化为

  1)令delta[s] = delta[s] + d,表示将A[s]...A[n]同时增加d,但这样A[t+1]...A[n]就多加了d,所以

  2)再令delta[t+1] = delta[t+1] - d,表示将A[t+1]...A[n]同时减d

 

      然后来看查询操作query(s, t),求A[s]...A[t]的区间和,转化为求前缀和,设sum[i] = A[1]+...+A[i],则

                            A[s]+...+A[t] = sum[t] - sum[s-1],

  那么前缀和sum[x]又如何求呢?它由两部分组成,一是数组的原始和,二是该区间内的累计增量和, 把数组A的原始值保存在数组org中,

  并且delta[i]对sum[x]的贡献值为delta[i]*(x+1-i),那么  

                             sum[x] = org[1]+...+org[x] + delta[1]*x + delta[2]*(x-1) + delta[3]*(x-2)+...+delta[x]*1

                                         = org[1]+...+org[x] + segma(delta[i]*(x+1-i))

                                         = segma(org[i]) + (x+1)*segma(delta[i]) - segma(delta[i]*i),1 <= i <= x

          =segma(org[i]-delta[i]*i)+(x+1)*delta[i],  i<=1<=x  

  这其实就是三个数组org[i], delta[i]和delta[i]*i的前缀和,org[i]的前缀和保持不变,事先就可以求出来,delta[i]和delta[i]*i的前缀和是不断变化的,可以用两个树状数组来维护。

 

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 using namespace std;
14 typedef long long LL;
15 const int MAXN = 100011;
16 int n,m;
17 int a[MAXN];
18 LL sum[MAXN],c1[MAXN],c2[MAXN],ans;
19 char ch[12];
20 
21 inline int getint()
22 {
23        int w=0,q=0; char c=getchar();
24        while((c<0 || c>9) && c!=-) c=getchar(); if(c==-) q=1,c=getchar(); 
25        while (c>=0 && c<=9) w=w*10+c-0, c=getchar(); return q ? -w : w;
26 }
27 
28 inline void add(LL x,LL val){
29     LL cun=x;
30     while(x<=n) {
31     c1[x]+=val; c2[x]+=val*cun;
32     x+=x&(-x);
33     }
34 }
35 
36 inline LL query(LL x){
37     LL total=0; LL cun=x;
38     while(x>0) {
39     total+=c1[x]*(cun+1)-c2[x];
40     x-=x&(-x);
41     }
42     return total;
43 }
44 
45 inline LL count(LL l,LL r){
46     return query(r)-query(l-1);
47 }
48 
49 inline void work(){
50     n=getint(); m=getint(); for(int i=1;i<=n;i++) a[i]=getint(),sum[i]=sum[i-1]+a[i];
51     int l,r; LL val;
52     while(m--) {
53     scanf("%s",ch);    
54     if(ch[0]==C) {
55         l=getint(); r=getint(); val=getint();
56         add(l,val); add(r+1,-val);
57     } else{
58         l=getint(); r=getint();
59         ans=sum[r]-sum[l-1]; ans+=count(l,r);
60         printf("%lld\n",ans);
61     }
62     }
63 }
64 
65 int main()
66 {
67   work();
68   return 0;
69 }

 

POJ3468 A Simple Problem with Integers

标签:

原文地址:http://www.cnblogs.com/ljh2000-jump/p/5866269.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!