A Simple Problem with Integers
Time Limit: 5000msMemory Limit: 131072KB 64-bit integer IO format: %lld Java class name: Main
Submit Status PID: 7955
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.
讲道理。。这道题当时卡了我很久,因为不知道lazy这个东西。。。
唉缺课就是不好o(`ω´ )o
然后但是知道了lazy之后写,还是卡了窝很久呜呜呜
区间查询的复杂度仍然是log2N的,但是区间修改如果仍然是从上到下每个区间都要更新的话,复杂度就很高了。(eg.[l,r]是需要更新的区间,按着单点更新的方式,就会从上到下所有[l,r]的子区间都要更新,但这样复杂度比O(n)还高,得不偿失)
但是我们发现其实没有必要每个区间都更新。因为如果要更新的区间刚好是某个节点的边界的话,我们只需要记录下来这个区间的增量是多少就可以了,并不需要接着向下更新。
如果要查询的这个区间是 我们记录了inc值的节点的子区间,那么我们就只需要把这个inc值沉降给儿子们,然后这个儿子区间真实是sum=sum+inc(r-l+1)这个值。
这样复杂度就又变回了log2n=-=
这里的pushdown函数就是一个沉降inc值的过程。
这就是一个lazy 的思想,也是一个继承的思想。(从父亲那里继承一些东西,这样可以少做很多事情)
int pushdown(int mid,int v){
if(tree[v].inc==0) return 0;
tree[mid].inc+=tree[v].inc;
tree[mid+1].inc+=tree[v].inc;
tree[mid].sum+=tree[v].inc*(tree[mid].r-tree[mid].l+1);
tree[mid+1].sum+=tree[v].inc*(tree[mid+1].r-tree[mid+1].l+1);
tree[v].inc=0;
return 0;
}
虽然我用了lazy 还是wa了两发,是因为当时理解的还不透彻。
在更新的时候,我的判断条件写的比较丑陋=-=
忽略了 更新完儿子们的sum值之后要把父亲也给更新了
虽然父亲把inc 沉降给了儿子,但儿子接下来还会再增加值,如果不加给父亲,那么父亲所存的sum就不正确了=-=
也就是一个pushup的过程
现在想想理所应当 感觉很自然,但当时就是制杖。。。
tree[v].sum=tree[v<<1].sum+tree[v<<1|1].sum;
// Created by ZYD in 2015.
// Copyright (c) 2015 ZYD. All rights reserved.
//
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define Size 100000
#define ll long long
#define mk make_pair
#define pb push_back
#define mem(array) memset(array,0,sizeof(array))
typedef pair<int,int> P;
struct date{
ll l;
ll r;
long long sum,inc;
}tree[500000];
int build(ll L,ll R,int v){
tree[v].l=L;
tree[v].r=R;
tree[v].inc=0;
if(L==R){
scanf("%lld",&tree[v].sum);
return 0;
}
int mid=(L+R)>>1;
build(L,mid,v<<1);
build(mid+1,R,v<<1|1);
// tree[v].w=tree[v<<1].w+tree[(v<<1)+1].w;
tree[v].sum=tree[v<<1].sum+tree[v<<1|1].sum;
return 0;
}
int pushdown(int mid,int v){
if(tree[v].inc==0) return 0;
tree[mid].inc+=tree[v].inc;
tree[mid+1].inc+=tree[v].inc;
tree[mid].sum+=tree[v].inc*(tree[mid].r-tree[mid].l+1);
tree[mid+1].sum+=tree[v].inc*(tree[mid+1].r-tree[mid+1].l+1);
tree[v].inc=0;
return 0;
}
int update(int v,ll x,ll y,long long c){
if(tree[v].l==x && y==tree[v].r){
tree[v].sum+=c*(y-x+1);
tree[v].inc+=c;
return 0;
}
if(tree[v].l==tree[v].r){
return 0;
}
//如果上面没有return 则说明这里需要向子区间传递inc
int mid=v<<1;
int flag=0;
pushdown(mid,v);//本身v区间增加的值 传递给儿子们
if(y<=tree[mid].r){
update(mid,x,y,c);
flag=1;
}
if(tree[mid+1].l<=x){
update(mid+1,x,y,c);
flag=1;
}
if(flag==0){
update(mid,x,tree[mid].r,c);
update(mid+1,tree[mid+1].l,y,c);
}
tree[v].sum=tree[v<<1].sum+tree[v<<1|1].sum;
return 0;
}
long long ask(int v,int x,int y){
if(tree[v].l==x && tree[v].r==y) return tree[v].sum;
int mid=v<<1;
pushdown(mid,v);
if(tree[mid].r>=y){
return ask(mid,x,y);
}
if(tree[mid+1].l<=x) return ask(mid+1,x,y);
return (ask(mid,x,tree[mid].r)+ask(mid+1,tree[mid+1].l,y));
}
int main()
{
//freopen("in.txt","r",stdin);
int N,Q,x,y;
long long a;
char ch;
scanf("%d%d",&N,&Q);
build(1,N,1);
/*for(int i=1;i<=N;i++){
scanf("%lld",&a);
update(1,i,i,a);
}*/
getchar();//cout<<tree[1].inc<<"*"<<endl;
// cout<<tree[1].l<<tree[1].r<<tree[1].sum<<endl;
for(int i=1;i<=Q;i++){
scanf("%c %d %d",&ch,&x,&y);
// cout<<ch;
if(ch=='C'){
scanf("%lld",&a);
// cout<<x<<y<<"**";
update(1,x,y,a);
}
if(ch=='Q'){
// cout<<i<<"*"<<x<<y;
printf("%lld\n",ask(1,x,y));
}
getchar();
}
return 0;
}