例题
「POJ3468」A Simple Problem with Integers
时间限制: 1 Sec 内存限制: 128 MB
题目描述
你有一些整数,和一些操作与询问需要处理
输入
第一行:N,Q,1 ≤ N,Q ≤ 100000.
第二行:N个整数, A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000
接下来:Q行,表示操作与询问
C a b c 表示,区间[a,b]全部增加c,-10000 ≤ c ≤ 10000.
Q a b 表示求区间[a,b]的和
输出
每个询问一个结果,一行。
样例输入
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
样例输出
4
55
9
15
分析
显然是用线段树,但是是修改区间,如果用循环会超时,所以我们用线段树+lazy标记。
还有,注意数据范围,要用long long(我也被卡了一次)。
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define full(a,b,c) fill(b,b+sizeof a/4,c)
#define N 100000+5
int n,m,arr[N];
long long s[4*N],lazy[4*N];//注意数据!
void built(int k,int l,int r)//建树
{
if(l==r)
{
s[k]=1LL*arr[l];
return;
}
int mid=(l+r)>>1;
built(k*2,l,mid);
built(k*2+1,mid+1,r);
s[k]=s[k*2]+s[k*2+1];
}
void pushdown(int k,int l,int r)//把k的懒传递给儿子
{
if(!lazy[k])return;//不懒
int mid=(l+r)>>1;
s[k*2]+=(mid-l+1)*lazy[k];//左儿子
lazy[k*2]+=lazy[k];
s[2*k+1]+=(r-mid)*lazy[k];//右儿子
lazy[k*2+1]+=lazy[k];
lazy[k]=0;//传递后就不懒了
}
void update(int k,int l,int r,int x,int y,int v)//把[x~y]+v
{
if(x>r||y<l)return;
if(x<=l&&r<=y)//包含
{
s[k]+=1LL*(r-l+1)*v;//有(r-l+1)个数
lazy[k]+=1LL*v;//标记我懒了
return;
}//不包含
int mid=(l+r)>>1;
pushdown(k,l,r);//先传递父亲的懒
update(k*2,l,mid,x,y,v);
update(k*2+1,mid+1,r,x,y,v);
s[k]=s[k*2]+s[k*2+1];
}
long long ask(int k,int l,int r,int x,int y)//询问[x~y]的和
{
if(x>r||y<l)return 0;
if(x<=l&&r<=y)return s[k];
int mid=(l+r)>>1;
pushdown(k,l,r);//先传递父亲的懒
return ask(k*2,l,mid,x,y)+ask(k*2+1,mid+1,r,x,y);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&arr[i]);
built(1,1,n);
for(int i=1; i<=m; i++)
{
char flag;
scanf("\n%c",&flag);
// printf("%c*\n",flag);
if(flag=='C')
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
update(1,1,n,a,b,c);
}
if(flag=='Q')
{
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",ask(1,1,n,a,b));
}
}
}
虽然可以懒标记,但是打代码别懒。(其实我也想懒 )