• POJ3468 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.

    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
    ",ans);
    61     }
    62     }
    63 }
    64 
    65 int main()
    66 {
    67   work();
    68   return 0;
    69 }
  • 相关阅读:
    自己设计的SSO登录流程图
    Java泛型:泛型类、泛型接口和泛型方法
    Java中泛型的各种使用
    Java总结篇系列:Java泛型
    java生成MD5校验码
    Android SQLite数据库之事务的学习
    Android SQLite详解
    android删除表和清空表
    Android 软键盘自动弹出和关闭
    java中表示二进制、八进制、十进制、十六进制
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5866269.html
Copyright © 2020-2023  润新知