• A Simple Problem with Integers(POJ 3468)


    • 原题如下:
      A Simple Problem with Integers
      Time Limit: 5000MS   Memory Limit: 131072K
      Total Submissions: 142057   Accepted: 44088
      Case Time Limit: 2000MS

      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.
    • 题解1:先考虑利用线段树,每个节点维护两个数据:①给这个节点对应的区间内的所有元素共同加上的值 ②在这个节点对应的区间中除去①之外其它的值的和。通过单独维护共同加上的值,给区间同时加一个值的操作就可以高效地进行了,如果对于父亲节点同时加了一个值,那么这个值就不会在儿子节点被重复考虑。在递归计算和时再把这一部分的值加到结果里面就可以了。这样不论是同时加一个值还是查询一段的和复杂度都是O(log n).
    • 代码1:
       1 #include <cstdio>
       2 #include <cctype>
       3 #include <cmath>
       4 #define number s-'0'
       5 
       6 using namespace std;
       7 
       8 const int MAX_N=100000;
       9 const int MAX_Q=100000;
      10 const int DAT_SIZE=(1<<18)-1;
      11 int N,Q;
      12 int A[MAX_N];
      13 char T[MAX_Q];
      14 int L[MAX_Q], R[MAX_Q], X[MAX_Q];
      15 long long data[DAT_SIZE], datb[DAT_SIZE];
      16 
      17 void read(int &x){
      18     char s;
      19     x=0;
      20     bool flag=0;
      21     while(!isdigit(s=getchar()))
      22         (s=='-')&&(flag=true);
      23     for(x=number;isdigit(s=getchar());x=x*10+number);
      24     (flag)&&(x=-x);
      25 }
      26 
      27 void write(int x)
      28 {
      29     if(x<0)
      30     {
      31         putchar('-');
      32         x=-x;
      33     }
      34     if(x>9)
      35         write(x/10);
      36     putchar(x%10+'0');
      37 }
      38 
      39 int min(int x, int y)
      40 {
      41     if (x<y) return x;
      42     return y;
      43 }
      44 
      45 int max(int x, int y)
      46 {
      47     if (x>y) return x;
      48     return y;
      49 }
      50 
      51 void solve();
      52 void add(int a, int b, int x, int k, int l, int r);
      53 long long sum(int a, int b, int k, int l, int r); 
      54 
      55 int main()
      56 {
      57     read(N);read(Q);
      58     for (int i=0; i<N; i++) read(A[i]);
      59     for (int i=0; i<Q; i++)
      60     {
      61         scanf("%c", &T[i]);
      62         if (T[i]=='Q') {read(L[i]);read(R[i]);}
      63         else {read(L[i]);read(R[i]);read(X[i]);}
      64     }
      65     solve();
      66 }
      67 
      68 void solve()
      69 {
      70     for (int i=0; i<N; i++) add(i, i+1, A[i], 0, 0, N);
      71     for (int i=0; i<Q; i++)
      72         if (T[i]=='C') add(L[i]-1, R[i], X[i], 0, 0, N);
      73         else printf("%lld
      ", sum(L[i]-1, R[i], 0, 0, N));
      74 }
      75 
      76 void add(int a, int b, int x, int k, int l, int r)
      77 {
      78     if (a<=l && r<=b) data[k]+=x;
      79     else if (l<b && r>a)
      80     {
      81         datb[k]+=(min(b,r)-max(a,l))*x;
      82         add(a, b, x, k*2+1, l, (l+r)/2);
      83         add(a, b, x, k*2+2, (l+r)/2, r);
      84     }
      85 }
      86 
      87 long long sum(int a, int b, int k, int l, int r)
      88 {
      89     if (b<=l || a>=r) return 0;
      90     else if(l>=a && r<=b) return data[k]*(r-l)+datb[k];
      91     else 
      92     {
      93         long long res=(min(b,r)-max(a,l))*data[k];
      94         res+=sum(a, b, k*2+1, l, (l+r)/2);
      95         res+=sum(a, b, k*2+2, (l+r)/2, r);
      96         return res;
      97     }
      98 }
    • 题解2:树状数组也可以通过在每个节点上维护两个数据,高效地进行上述操作。如果给区间[l,r]同时加上x的话,考虑每个节点的值会如何变化。令s(i)是加上x之前的前缀和,s'(i)是加上x之后的前缀和。那么就有:
      i<l→s'(i)=s(i)
      l≤i≤r→s'(i)=s(i)+x*(i-l+1)
                      =s(i)+x*i-x*(l-1)
      r<i→s'(i)=s(i)+x*(r-l+1)
      下面记sum(bit,i)为树状数组bit的前i项和。我们构建两个树状数组bit0和bit1,并且设∑(j=1,i)aj=sum(bit1,i)*i+sum(bit0,i)
      那么在[l,r]区间上同时加上x就可以看成是
      1.在bit0的l位置加上-x(l-1)
      2.在bit1的l位置加上x
      3.在bit0的r+1位置加上xr
      4.在bit1的r+1位置加上-x
      这4个操作。因此查询和更新操作都可以在O(log n)时间里完成。
      更一般地,如果操作得到的结果可以用i的n次多项式表示,那么就可以使用n+1个树状数组来进行维护了。
    • 代码2:
       1 #include <cstdio>
       2 #include <cctype>
       3 #include <cmath>
       4 #define number s-'0'
       5 
       6 using namespace std;
       7 
       8 const int MAX_N=100000;
       9 const int MAX_Q=100000;
      10 int N,Q;
      11 int A[MAX_N+1]; 
      12 char T[MAX_Q];
      13 int L[MAX_Q], R[MAX_Q], X[MAX_Q];
      14 long long bit0[MAX_N+1], bit1[MAX_N+1];
      15 
      16 
      17 void read(int &x){
      18     char s;
      19     x=0;
      20     bool flag=0;
      21     while(!isdigit(s=getchar()))
      22         (s=='-')&&(flag=true);
      23     for(x=number;isdigit(s=getchar());x=x*10+number);
      24     (flag)&&(x=-x);
      25 }
      26 
      27 void write(long long x)
      28 {
      29     if(x<0)
      30     {
      31         putchar('-');
      32         x=-x;
      33     }
      34     if(x>9)
      35         write(x/10);
      36     putchar(x%10+'0');
      37 }
      38 
      39 long long sum(long long *b, int i)
      40 {
      41     long long s=0;
      42     while (i>0)
      43     {
      44         s+=b[i];
      45         i=i&(i-1);
      46     }
      47     return s;
      48 }
      49 
      50 void add(long long *b, int i, int v)
      51 {
      52     while (i<=N)
      53     {
      54         b[i]+=v;
      55         i+=i&-i;
      56     }
      57 }
      58 
      59 void solve();
      60 
      61 int main()
      62 {
      63     read(N);read(Q);
      64     for (int i=1; i<=N; i++) read(A[i]);
      65     for (int i=0; i<Q; i++)
      66     {
      67         scanf("%c", &T[i]);
      68         if (T[i]=='Q') {read(L[i]);read(R[i]);}
      69         else {read(L[i]);read(R[i]);read(X[i]);}
      70     }
      71     solve();
      72 }
      73 
      74 void solve()
      75 {
      76     for (int i=1; i<=N; i++)
      77     {
      78         add(bit0, i, A[i]);
      79     }
      80     for (int i=0; i<Q; i++)
      81     {
      82         if (T[i]=='C')
      83         {
      84             add(bit0, L[i], -X[i]*(L[i]-1));
      85             add(bit1, L[i], X[i]);
      86             add(bit0, R[i]+1, X[i]*R[i]);
      87             add(bit1, R[i]+1, -X[i]);
      88         }
      89         else
      90         {
      91             long long res=0;
      92             res+=sum(bit0, R[i])+sum(bit1, R[i])*R[i];
      93             res-=sum(bit0, L[i]-1)+sum(bit1, L[i]-1)*(L[i]-1);
      94             printf("%lld
      ", res);
      95         }
      96     }
      97 }
  • 相关阅读:
    配置sql server 2000以允许远程访问
    SQLServer大数据量插入BULK INSERT
    【项目经理之修炼(5)】《基础篇》别把项目成功当目标(转)
    C#XML文件操作类
    winform窗体总在所有窗体最上层
    配置VSS2005的Internet访问(转)
    U盘引导盘制作
    【项目经理之修炼(4)】《基础篇》故事的主角是你吗?(转)
    SQLServer收缩数据库日志
    【项目经理之修炼(1)】《序章》关于要写给谁看的问题(转)
  • 原文地址:https://www.cnblogs.com/Ymir-TaoMee/p/9544756.html
Copyright © 2020-2023  润新知