kuangbin专题七 POJ3468 A Simple Problem with Integers (线段树或树状数组)

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


区间修改 区间查询 注意pushdown的操作就可以了

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <math.h>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <string>
  7 #include <vector>
  8 #include <set>
  9 #include <map>
 10 #include <queue>
 11 #include <algorithm>
 12 #include <sstream>
 13 #include <stack>
 14 using namespace std;
 15 #define FO freopen("in.txt","r",stdin);
 16 #define rep(i,a,n) for (int i=a;i<n;i++)
 17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
 18 #define pb push_back
 19 #define mp make_pair
 20 #define all(x) (x).begin(),(x).end()
 21 #define fi first
 22 #define se second
 23 #define SZ(x) ((int)(x).size())
 24 #define debug(x) cout << "&&" << x << "&&" << endl;
 25 #define lowbit(x) (x&-x)
 26 #define mem(a,b) memset(a, b, sizeof(a));
 27 typedef vector<int> VI;
 28 typedef long long ll;
 29 typedef pair<int,int> PII;
 30 const ll mod=1000000007;
 31 const int inf = 0x3f3f3f3f;
 32 ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
 33 ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
 34 //head
 35 
 36 //区间修改 区间查询
 37 const int maxx=100010;
 38 ll sum[maxx<<2],lazy[maxx<<2],val;
 39 int n,q;
 40 
 41 void Pushup(int rt) {
 42     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 43 }
 44 
 45 void build(int rt,int L,int R) {
 46     lazy[rt]=0;
 47     if(L==R) {
 48         scanf("%lld",&sum[rt]);
 49         return;
 50     }
 51     int mid=(L+R)>>1;
 52     build(rt<<1,L,mid);
 53     build(rt<<1|1,mid+1,R);
 54     Pushup(rt);
 55 }
 56 
 57 void Pushdown(int rt,int x) {
 58     if(lazy[rt]) {
 59         lazy[rt<<1]+=lazy[rt];
 60         lazy[rt<<1|1]+=lazy[rt];
 61         sum[rt<<1]+=(x-(x>>1))*lazy[rt];//左子树加左边一半的值
 62         sum[rt<<1|1]+=(x>>1)*lazy[rt];//右子树同理
 63         lazy[rt]=0;//清空
 64     }    
 65 }
 66 
 67 void Updata(int rt,int L,int R,int l,int r) {
 68     if(L>=l&&R<=r) {
 69         lazy[rt]+=val;//累加标记
 70         sum[rt]+=(R-L+1)*val;//更新值
 71         return;
 72     }
 73     int mid=(L+R)>>1;
 74     Pushdown(rt,R-L+1);//这里多了一个参数 L R区间的个数
 75     if(l<=mid) Updata(rt<<1,L,mid,l,r);
 76     if(r>mid) Updata(rt<<1|1,mid+1,R,l,r);
 77     Pushup(rt);
 78 }
 79 
 80 ll Query(int rt,int L,int R,int l,int r) {
 81     if(L>=l&&R<=r)
 82         return sum[rt];
 83     ll ans=0;
 84     int mid=(L+R)>>1;
 85     Pushdown(rt,R-L+1);
 86     if(l<=mid) ans+=Query(rt<<1,L,mid,l,r);
 87     if(r>mid) ans+=Query(rt<<1|1,mid+1,R,l,r);
 88     Pushup(rt);
 89     return ans;
 90 }
 91 
 92 
 93 int main() {
 94     while(~scanf("%d%d",&n,&q)) {
 95         build(1,1,n);
 96         char s[3];
 97         while(q--) {
 98             scanf("%s",s);
 99             int l,r;
100             if(s[0]=='Q') {
101                 scanf("%d%d",&l,&r);
102                 printf("%lld
",Query(1,1,n,l,r));
103             } else {
104                 scanf("%d%d%lld",&l,&r,&val);
105                 Updata(1,1,n,l,r);
106             }
107         }
108     }
109 }
View Code

借此机会学习了一波树状数组,有点难理解。

单点修改 区间查询  Updata(l,val)

区间修改 单点查询  引入差分数组 c[i]=d[i]-d[i-1]; Updata(l,val);  Updata(r+1,-val); ----明白树状数组就好理解了。把多加的减去

区间修改 区间查询  公式可以推到一下,sum[n]=n*(c[1]+c[2]+...c[n])-(0*c[1]+1*c[2]+2*c[3]+...+(n-1)*c[n]);

所以再维护一个 (i-1)*(a[i]-a[i-1]) , a为原数组。

Updata(l,(l-1)*val); Updata(r+1,-r*val);   原理同上。多加的减去。

(纯属个人理解。关键还是公式的推导,和树状数组的理解)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 #define lowbit(x) (x&-x)
 7  
 8 int n,q;
 9 const int maxn=100010;
10 ll a[maxn],val,c1[maxn],c2[maxn];//维护两个树状数组
11 
12 void Updata(ll c[],int pos,ll val) {
13     while(pos<=n) {
14         c[pos]+=val;
15         pos+=lowbit(pos);
16     }
17 } 
18 
19 ll getsum(ll c[],int pos) {
20     ll ans=0;
21     while(pos>0) {
22         ans+=c[pos];
23         pos-=lowbit(pos);
24     }
25     return ans;
26 }
27 
28 ll sigma(int r) {//公式推导
29     ll sum1=r*getsum(c1,r);
30     ll sum2=getsum(c2,r);
31     return sum1-sum2;
32 }
33 
34 ll Query(int l,int r) {//区间求和
35     return sigma(r)-sigma(l-1);
36 }
37 
38 int main() {
39     while(~scanf("%d%d",&n,&q)) {
40         memset(c1,0,sizeof(c1));memset(c2,0,sizeof(c2));
41         for(int i=1;i<=n;i++) { 
42             scanf("%lld",&a[i]);
43             Updata(c1,i,a[i]-a[i-1]);//维护a[i]-a[i-1]
44             Updata(c2,i,(i-1)*(a[i]-a[i-1]));//维护(i-1)*(a[i]-a[i-1])
45         } 
46         char s[2];
47         while(q--) {
48             int l,r;
49             scanf("%s",s);
50             if(s[0]=='Q') {
51                 scanf("%d%d",&l,&r);
52                 printf("%lld
",Query(l,r));
53             } else {
54                 scanf("%d%d%lld",&l,&r,&val);
55                 //更新操作有点难理解
56                 Updata(c1,l,val);Updata(c1,r+1,-val);
57                 Updata(c2,l,(l-1)*val);Updata(c2,r+1,-r*val);
58             }
59         }
60     }
61 }
View Code
原文地址:https://www.cnblogs.com/ACMerszl/p/9839767.html