L i n k Link Link
l u o g u luogu luogu P 3372 P3372 P3372
D e s c r i p t i o n Description Description
给出一堆数,形成一个区间,对于这个区间,有两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
I n p u t Input Input
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和
O u t p u t Output Output
输出包含若干行整数,即为所有操作2的结果。
S a m p l e Sample Sample I n p u t Input Input
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
S a m p l e Sample Sample O u t p u t Output Output
11
8
20
H i n t Hint Hint
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
T r a i n Train Train o f of of T h o u g h t Thought Thought
我们可以用线段树来做这一道题目,但是一般的线段树也不够,因为数据加强过,所以我们要加入 l a z y lazy lazy操作(用于存储某一个给子节点的数,当子节点被询问时再加下去)
C o d e Code Code
#include<iostream>
#include<cstdio>
using namespace std;
int N,M; long long a[100005];
struct Tree_1
{
int l,r;
long long lazy,val;
}tree[400005];//l,r表示这个节点区间的左右两边,lazy表示存储的数,val表示当前区间的值
void Up(int tt)
{tree[tt].val=tree[tt*2].val+tree[tt*2+1].val;}
void Down(int tt,int m)
{
if (tree[tt].lazy) {
tree[tt*2].lazy+=tree[tt].lazy;
tree[tt*2+1].lazy+=tree[tt].lazy;
tree[tt*2].val+=tree[tt].lazy*(m-(m/2));
tree[tt*2+1].val+=tree[tt].lazy*(m/2);
tree[tt].lazy=0;
}
}
void Build(int l,int r,int tt)
{
tree[tt].l=l; tree[tt].r=r;
if (l==r)
{
tree[tt].val=a[l];
return;
}
int mid=(l+r)/2;
Build(l,mid,tt*2);
Build(mid+1,r,tt*2+1);
Up(tt);//向上返回值
}//建树
void Change(int l,int r,int tt,int k)
{
if (tree[tt].l==l && r==tree[tt].r) { //符合区间
tree[tt].val+=(long long)(r-l+1)*k;//求区间总和
tree[tt].lazy+=k;//lazy操作
return ;
}
if (tree[tt].l==tree[tt].r) return;
Down(tt,tree[tt].r-tree[tt].l+1);//向下赋值
int mid=(tree[tt].l+tree[tt].r)/2;
if (l<=r && mid>=r) Change(l,r,tt*2,k);//剩余区间全部在左边
else if (l>mid && l<=r) Change(l,r,tt*2+1,k); //剩余区间全部在右边
else {
if (l<=mid) Change(l,mid,tt*2,k);//左子节点
if (r>mid) Change(mid+1,r,tt*2+1,k);//右子节点
}
Up(tt);//向上递增
}
long long Find(int l,int r,int tt)
{
if (tree[tt].l==l && r==tree[tt].r) return tree[tt].val;
Down(tt,tree[tt].r-tree[tt].l+1); //向下赋值
int mid=(tree[tt].l+tree[tt].r)/2; long long ans=0;
if (l<=r && mid>=r) ans+=Find(l,r,tt*2);//和Change的步骤同理
else if (l>mid && l<=r) ans+=Find(l,r,tt*2+1);
else
{
if (l<=mid) ans+=Find(l,mid,tt*2);
if (r>mid) ans+=Find(mid+1,r,tt*2+1);
}
return ans;
}
int main()
{
scanf("%d%d",&N,&M);
for (int i=1; i<=N; ++i)
scanf("%lld",&a[i]);
Build(1,N,1); //建树操作
for (int i=1; i<=M; ++i)
{
int t,x,y,k;
scanf("%d%d%d",&t,&x,&y);
if (t==1) {
scanf("%d",&k);
Change(x,y,1,k);//对应操作1
}
else printf("%lld\n",Find(x,y,1));//对应操作2
}
}