题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数数加上x
2.求出某一个数的和
输入输出格式
输入格式:
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含2或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x 含义:输出第x个数的值
输出格式:
输出包含若干行整数,即为所有操作2的结果。
输入输出样例
输入样例#1: 复制
5 5 1 5 4 2 3 1 2 4 2 2 3 1 1 5 -1 1 3 5 7 2 4
输出样例#1: 复制
6 10
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
样例说明:
故输出结果为6、10
PS:应该很多人看到区间修改和我一样想到了线段树吧,但是看到标题是要用树状数组感觉有点吃惊,后面去看了一下,不得不佩服大佬的思想,这个题只求x的值,所以可以用差分来做,简单的解释一下,例如有数组a[]={1, 5 , 6 , 7 ,4 , 5};差分数组就是c[]={1, 4, 1, 1, -3, 1};可以看出a[x]=c[1]+…+c[x];现在【2,4】+3;a数组变成a[]={1, 7 , 8, 9 ,4 , 5};,c数组变成c[]={1, 6, 1, 1, -5, 1};数组只有a[1]和a[5]变了,a[1]+2,a[5]-2;,所以我们每次只改变两个数就可以了,可以看代码理解下,思想很巧妙。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=5e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
typedef long long ll;
using namespace std;
ll num[maxn];
int n,m;
ll getsum(int x)
{
ll sum=0;
while(x)
{
sum+=num[x];
x-=lowbit(x);
}
return sum;
}
void pushdata(int x,int k)
{
while(x<=n)
{
num[x]+=k;
x+=lowbit(x);
}
}
int main()
{
cin>>n>>m;
int t=0,t1;
for(int i=1;i<=n;i++)
{
scanf("%d",&t1);
pushdata(i,t1-t);
t=t1;
}
while(m--)
{
int a,x,y,k;
scanf("%d",&a);
if(a==1)
{
scanf("%d%d%d",&x,&y,&k);
pushdata(x,k);
pushdata(y+1,-k);
}
else
{
scanf("%d",&x);
printf("%lld\n",getsum(x));
}
}
return 0;
}