您的位置:首页 > 其它

codevs 1082 线段树练习 3

2017-03-22 20:17 330 查看
1082 线段树练习 3 区间修改,区间查询;

时间限制: 3 s

空间限制: 128000 KB

题目等级 : 大师 Master

给你N个数,有两种操作:

1:给区间[a,b]的所有数增加X

2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

再接下来一个正整数Q,每行表示操作的个数,

如果第一个数是1,后接3个正整数,

表示在区间[a,b]内每个数增加X,如果是2,

表示操作2询问区间[a,b]的和是多少。

pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000

1<=q<=200000

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sz=200000+50;
struct seg_tree{
int l,r;
long long sum;
long long ax;
} t[sz<<2];
int n,a,q,x,y,z;
long long  v[sz];
void updata(int m){
t[m].sum=t[m<<1].sum+t[m<<1|1].sum;
return ;
}
void build(int m,int ll,int rr){
t[m].l=ll,t[m].r=rr;
if(ll==rr) {
t[m].sum=v[ll];
return ;
}
int mid=(ll+rr)>>1;
build(m<<1,ll,mid);
build(m<<1|1,mid+1,rr);
updata(m);
}
void add(int m,int vv){
t[m].sum+=(t[m].r-t[m].l+1)*vv;
t[m].ax+=vv;
return ;
}
void spread(int m){
if(t[m].ax){
add(m<<1,t[m].ax);
add(m<<1|1,t[m].ax);
t[m].ax=0;
//这里要改为0!! 否则用while会死循环
}
return ;
}
long long ask(int m,int ll,int rr){
if(t[m].l>=ll&&t[m].r<=rr) return t[m].sum;
int mid=t[m].l+t[m].r>>1;
long long ans=0;
spread(m);
if(mid>=ll) ans+=ask(m<<1,ll,rr);
if(mid<rr) ans+=ask(m<<1|1,ll,rr);
return ans;
}
void change(int m,int ll,int rr,int vv){
if(t[m].l>=ll&&t[m].r<=rr) {
add(m,vv);return;
}
int mid=(t[m].l+t[m].r)>>1;
spread(m);
if(mid>=ll) change(m<<1,ll,rr,vv);
if(mid<rr) change(m<<1|1,ll,rr,vv);
updata(m);
return ;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
build(1,1,n);

scanf("%d",&q);
while(q--){
scanf("%d",&a);
if(a==1){
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z);
//  for(int i=1;i<=n*4;i++)
//printf("i= %d  t[i].l= %d  t[i].r= %d  t[i].sum= %d  t[i].ax= %d\n",i,t[i].l,t[i].r,t[i].sum,t[i].ax);
}
else scanf("%d%d",&x,&y),printf("%lld\n",ask(1,x,y));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: