【模板】樹狀陣列(差分)
阿新 • • 發佈:2018-11-09
題目描述
如題,已知一個數列,你需要進行下面兩種操作:
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
題解:
來介紹一下差分
設陣列a[]={1,6,8,5,10},那麼差分陣列b[]={1,5,2,-3,5}
也就是說b[i]=a[i]-a[i-1];(a[0]=0;),那麼a[i]=b[1]+….+b[i];(這個很好證的)。
假如區間[2,4]都加上2的話
a陣列變為a[]={1,8,10,7,10},b陣列變為b={1,7,2,-3,3};
發現了沒有,b陣列只有b[2]和b[5]變了,因為區間[2,4]是同時加上2的,所以在區間內b[i]-b[i-1]是不變的.
所以對區間[x,y]進行修改,只用修改b[x]與b[y+1]:
b[x]=b[x]+k;b[y+1]=b[y+1]-k;
程式碼:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int a[2000010];
int n,i,m;
int lowbit(int k)
{
return k&(-k);
}
void add(int k,int num)//將第K位加num
{
while(k<=n)
{
a[k]+=num;
k+=lowbit(k);
}
}
int summ(int k) //求從1到K的和
{
int sum=0;
while(k>0)
{
sum+=a[k];
k-=lowbit(k);
}
return sum;
}
int main()
{
int temp,ans,pre=0;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d",&temp);
add(i,temp-pre); //初始化建樹 差分
pre=temp;
}
for(i=1;i<=m;i++)
{
int b,c,d,e;
cin>>b;
if(b==1)
{
cin>>c>>d>>e;
add(c,e);
add(d+1,-e);
}
else
{
cin>>c;
cout<<summ(c)<<endl;
}
}
return 0;
}