1. 程式人生 > >【模板】樹狀陣列(差分)

【模板】樹狀陣列(差分)

題目描述
如題,已知一個數列,你需要進行下面兩種操作:

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; }