POJ 3468 A Simple Problem with Integers

A Simple Problem with Integers

Time Limit: 5000ms
Memory Limit: 131072KB
This problem will be judged on PKU. Original ID: 3468
64-bit integer IO format: %lld      Java class name: Main
 

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 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

Source

 
解题:学习下树状数组的改段求段。。。确实很奇妙
 

给你一个数列,每次询问一个区间的和,或者每次将一个区间的所有元素都加上一个数

    树状数组天生用来动态维护数组前缀和,其特点是每次更新一个元素的值,查询只能查数组的前缀和,

但这个题目求的是某一区间的数组和,而且要支持批量更新某一区间内元素的值,怎么办呢?实际上,

还是可以把问题转化为求数组的前缀和。

    首先,看更新操作$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] imes (x+1-i)$,那么

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

                                         [= org[1]+...+org[x] + sum_{i = 1}^{x}(delta[i] imes (x+1-i))]

                                        [ sum[x] = sum_{i = 1}^{x}(org[i]) + (x+1) imessum_{i = 1}^{x}(delta[i]) - sum_{i = 1}^{x}(delta[i] imes i) ]

可以转化为 $sum_{i=1}^{x}(org[i]-delta[i]*i)+(x+1)*delta[i]$

这其实就是三个数组org[i], delta[i]和delta[i]*i的前缀和,org[i]的前缀和保持不变,事先就可以求出来,delta[i]和

delta[i]*i的前缀和是不断变化的,可以用两个树状数组来维护。

 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 using namespace std;
 5 typedef long long LL;
 6 const int maxn = 100010;
 7 LL s[maxn],c[2][maxn];
 8 int n,m;
 9 void add(LL *c,int i,LL val) {
10     while(i <= n) {
11         c[i] += val;
12         i += i&-i;
13     }
14 }
15 LL sum(LL *c,int i,LL ret = 0) {
16     while(i > 0) {
17         ret += c[i];
18         i -= i&-i;
19     }
20     return ret;
21 }
22 int main() {
23     char cmd[4];
24     LL x,y,z;
25     while(~scanf("%d%d",&n,&m)) {
26         memset(c,0,sizeof c);
27         for(int i = 1; i <= n; ++i) {
28             scanf("%lld",s + i);
29             s[i] += s[i-1];
30         }
31         while(m--) {
32             scanf("%s",cmd);
33             if(cmd[0] == 'C') {
34                 scanf("%lld%lld%lld",&x,&y,&z);
35                 add(c[0],x,z);
36                 add(c[0],y+1,-z);
37                 add(c[1],x,x*z);
38                 add(c[1],y+1,-z*(y+1));
39             } else {
40                 scanf("%lld%lld",&x,&y);
41                 printf("%lld
",s[y] - s[x-1] + (y+1)*sum(c[0],y) - sum(c[1],y) - x*sum(c[0],x-1) + sum(c[1],x-1));
42             }
43         }
44     }
45     return 0;
46 }
View Code

 然后是Splay,灰常灰常慢

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 typedef long long LL;
  6 const int maxn = 100010;
  7 int seq[maxn],n,m;
  8 struct SplayTree{
  9     int v[maxn],lazy[maxn],fa[maxn],ch[maxn][2],sz[maxn];
 10     LL sum[maxn];
 11     int tot,root;
 12     void newnode(int &x,int key,int f){
 13         v[x = ++tot] = key;
 14         fa[x] = f;
 15         lazy[x] = ch[x][0] = ch[x][1] = 0;
 16         sz[x] = 1;
 17     }
 18     void pushup(int x){
 19         sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + v[x];
 20         sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
 21     }
 22     void pushdown(int x){
 23         if(lazy[x]){
 24             lazy[ch[x][0]] += lazy[x];
 25             lazy[ch[x][1]] += lazy[x];
 26             sum[ch[x][0]] += (LL)lazy[x]*sz[ch[x][0]];
 27             sum[ch[x][1]] += (LL)lazy[x]*sz[ch[x][1]];
 28             v[ch[x][0]] += lazy[x];
 29             v[ch[x][1]] += lazy[x];
 30             lazy[x] = 0;
 31         }
 32     }
 33     void build(int &x,int L,int R,int f){
 34         if(L > R) return;
 35         int mid = (L + R)>>1;
 36         newnode(x,seq[mid],f);
 37         build(ch[x][0],L,mid - 1,x);
 38         build(ch[x][1],mid + 1,R,x);
 39         pushup(x);
 40     }
 41     void init(){
 42         tot = 0;
 43         newnode(root,0,0);
 44         newnode(ch[root][1],0,root);
 45         build(ch[ch[root][1]][0],1,n,ch[root][1]);
 46     }
 47     void rotate(int x,int kd){
 48         int y = fa[x];
 49         pushdown(y);
 50         pushdown(x);
 51         ch[y][kd^1] = ch[x][kd];
 52         fa[ch[x][kd]] = y;
 53         fa[x] = fa[y];
 54         ch[x][kd] = y;
 55         fa[y] = x;
 56         if(fa[x]) ch[fa[x]][y == ch[fa[x]][1]] = x;
 57         pushup(y);
 58     }
 59     void splay(int x,int goal){
 60         while(fa[x] != goal){
 61             if(fa[fa[x]] == goal) rotate(x,x == ch[fa[x]][0]);
 62             else{
 63                 int y = fa[x],z = fa[y],s = (y == ch[z][0]);
 64                 if(x == ch[y][s]){
 65                     rotate(x,s^1);
 66                     rotate(x,s);
 67                 }else{
 68                     rotate(y,s);
 69                     rotate(x,s);
 70                 }
 71             }
 72         }
 73         pushup(x);
 74         if(!goal) root = x;
 75     }
 76     void select(int k,int goal){
 77         int x = root;
 78         while(k != sz[ch[x][0]]){
 79             if(k < sz[ch[x][0]]) x = ch[x][0];
 80             else{
 81                 k -= sz[ch[x][0]] + 1;
 82                 x = ch[x][1];
 83             }
 84         }
 85         splay(x,goal);
 86     }
 87 }spt;
 88 int main(){
 89     char op[5];
 90     int x,y,z;
 91     while(~scanf("%d%d",&n,&m)){
 92         for(int i = 1; i <= n; ++i)
 93             scanf("%d",seq + i);
 94         spt.init();
 95         while(m--){
 96             scanf("%s%d%d",op,&x,&y);
 97             spt.select(x - 1,0);
 98             spt.select(y + 1,spt.root);
 99             int RL = spt.ch[spt.ch[spt.root][1]][0];
100             if(op[0] == 'C'){
101                 scanf("%d",&z);
102                 spt.lazy[RL] += z;
103                 spt.sum[RL] += z*spt.sz[RL];
104                 spt.v[RL] += z;
105             }else printf("%lld
",spt.sum[RL]);
106         }
107     }
108     return 0;
109 }
View Code
原文地址:https://www.cnblogs.com/crackpotisback/p/4784119.html