poj 3468 A Simple Problem with Integers(线段树区间lazy标记修改or树状数组)

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.
解题思路:题意很清楚,大区间修改和询问:线段树+lazy懒标记,or树状数组,详解在代码里,注意求和用long long类型!
AC代码一之线段树懒标记(2500ms):
 1 #include<string.h>
 2 #include<cstdio>
 3 using namespace std;
 4 typedef long long LL;
 5 const int maxn=100005;
 6 int n,q,a,b;LL c,s[maxn],lazy[maxn<<2],sum[maxn<<2];char ch;
 7 void build(int l,int r,int x){//建树基本操作
 8     int mid=(l+r)>>1;
 9     if(l==r){sum[x]=s[mid];return;}
10     build(l,mid,x<<1);
11     build(mid+1,r,x<<1|1);
12     sum[x]=sum[x<<1]+sum[x<<1|1];
13 }
14 void push_down(int x,int len){//下放懒标记
15     if(lazy[x]){
16         lazy[x<<1]+=lazy[x];//延迟修改量是叠加的,沿着子树可以继续更新下去
17         lazy[x<<1|1]+=lazy[x];
18         sum[x<<1]+=(LL)(len-(len>>1))*lazy[x];//更新左子节点的值:加上左区间长度乘上父节点的懒标记
19         sum[x<<1|1]+=(LL)(len>>1)*lazy[x];//更新右子节点的值:加上右区间长度乘上父节点的懒标记
20         lazy[x]=0;//同时标记父节点已经修改完成,即置懒标记为0
21     }
22 }
23 void modify(int l,int r,int x,LL c){
24     if(a<=l&&r<=b){//如果[a,b]包含了当前子区间[l,r],则直接进行懒标记,不再递归下去
25         lazy[x]+=c;//叠加懒标记值
26         sum[x]+=(LL)c*(r-l+1);//同时累加修改值乘上当前子区间的长度
27         return;
28     }
29     push_down(x,r-l+1);//如果修改区间不包含当前子区间,并且当前子区间有懒标记,则下放懒标记
30     int mid=(l+r)>>1;
31     if(b<=mid)modify(l,mid,x<<1,c);
32     else if(a>mid)modify(mid+1,r,x<<1|1,c);
33     else{
34         modify(l,mid,x<<1,c);
35         modify(mid+1,r,x<<1|1,c);
36     }
37     sum[x]=sum[x<<1]+sum[x<<1|1];//修改某个区间后还要向上更新父节点的值
38 }
39 LL query(int l,int r,int x){
40     if(a<=l&&r<=b)return sum[x];//如果访问的区间[a,b]包含子区间[l,r],直接返回返回当前区间的值
41     int mid=(l+r)>>1;
42     push_down(x,r-l+1);//如果不包含子区间,并且当前节点有被懒标记,则应下放懒标记,因为查询的区间可能更小(最小到叶子节点),为避免少计算,还要这步操作,此时就不用向上更新了,修改区间值才要
43     if(b<=mid)return query(l,mid,x<<1);
44     else if(a>mid)return query(mid+1,r,x<<1|1);
45     else return query(l,mid,x<<1)+query(mid+1,r,x<<1|1);
46 }
47 int main(){
48     scanf("%d%d",&n,&q);
49     for(int i=1;i<=n;++i)scanf("%lld",&s[i]);
50     memset(lazy,0,sizeof(lazy));//注意:将每个节点的懒标记都标记为0
51     build(1,n,1);//建树
52     while(q--){
53         getchar();//吃掉回车符避免对字符输入的影响
54         scanf("%c",&ch);
55         if(ch=='Q'){
56             scanf("%d%d",&a,&b);
57             printf("%lld\n",query(1,n,1));
58         }
59         else{
60             scanf("%d%d%lld",&a,&b,&c);
61             modify(1,n,1,c);
62         }
63     }
64     return 0;
65 }

 AC代码二之树状数组(2125ms):裸题,套一下树状数组区间查询和区间修改模板即可。

 1 #include<string.h>
 2 #include<cstdio>
 3 typedef long long LL;
 4 const int maxn=100005;
 5 LL n,q,l,r,k,val[maxn],sum1[maxn],sum2[maxn];char op;
 6 void add(LL *sum,LL x,LL val){
 7     while(x<=n){sum[x]+=val;x+=(x&-x);}
 8 }
 9 LL get_sum(LL *sum,LL x){
10     LL ans=0;
11     while(x>0){ans+=sum[x];x-=(x&-x);}
12     return ans;
13 }
14 LL ask(LL x){
15     return x*get_sum(sum1,x)-get_sum(sum2,x);
16 }
17 int main(){
18     while(~scanf("%lld%lld",&n,&q)){
19         memset(sum1,0,sizeof(sum1));
20         memset(sum2,0,sizeof(sum2));
21         memset(val,0,sizeof(val));
22         for(LL i=1;i<=n;++i){
23             scanf("%lld",&val[i]);
24             add(sum1,i,val[i]-val[i-1]);//维护差分数组
25             add(sum2,i,(i-1)*(val[i]-val[i-1]));
26         }
27         while(q--){
28             getchar();//吸收回车符避免对单个字符读取的影响
29             scanf("%c",&op);
30             if(op=='C'){
31                 scanf("%lld%lld%lld",&l,&r,&k);
32                 add(sum1,l,k),add(sum1,r+1,-k);
33                 add(sum2,l,(l-1)*k);add(sum2,r+1,-r*k);
34             }
35             else{
36                 scanf("%lld%lld",&l,&r);
37                 printf("%lld\n",ask(r)-ask(l-1));//区间查询[1,r]-[1,l-1]=[l,r]
38             }
39         }
40     }
41     return 0;
42 }

 

posted @ 2018-08-08 11:27  霜雪千年  阅读(207)  评论(0编辑  收藏  举报