AcWing243一個簡單的整數問題2(樹狀陣列+差分+字首和規律)
阿新 • • 發佈:2020-08-26
題目地址:https://www.acwing.com/problem/content/244/
題目描述:
給定一個長度為N的數列A,以及M條指令,每條指令可能是以下兩種之一:
1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
2、“Q l r”,表示詢問 數列中第 l~r 個數的和。
對於每個詢問,輸出一個整數表示答案。
輸入格式
第一行兩個整數N,M。
第二行N個整數A[i]。
接下來M行表示M條指令,每條指令的格式如題目描述所示。
輸出格式
對於每個詢問,輸出一個整數表示答案。
每個答案佔一行。
資料範圍
1≤N,M≤1e5,
|d|≤10000,
|A[i]|≤1000000000
題解:這是對樹狀陣列的更深一步的擴充套件:區間加、區間求和。所以需要解決兩個問題:區間加、區間和。區間加比較容易,直接差分就可以。至於區間和我們可以想辦法求出原序列a的字首和表示方法,b是原序列的差分陣列
這張圖片中的藍色的,每一行藍色的和都是一個元素a,分別表示a[1].....a[x].所以我們只需要求出a的字首和,那麼對於區間的和就顯而易見了。至於圖中的紅色是一個填補的作用,我們可以知道a的字首和就是藍色+紅色再減去紅色。首先,藍色+紅色=a[x]*(x+1),而a[x]可以由差分陣列b的字首和求出。紅色其實是i*b[i]的字首和。所以a的前x的和S[x]=b[i]的字首和*(x+1)-i*b[i]的字首和。所以查詢[l,r]=S[r]-S[l-1]
AC程式碼:
#include<iostream> #include<cstring> using namespace std; const int N=1e5+10; #define lowbit(x) (x&(-x)) #define ll long long int ll a[N]={0},b[N]={0},c[2][N]={0},n,m; void add(int k,int x,ll d){ while(x<=n){ c[k][x]+=d; x+=lowbit(x); } } ll sum(intk,int x){ ll sum=0; while(x>0){ sum+=c[k][x]; x-=lowbit(x); } return sum; } ll prefix_sum(int x){ return sum(0,x)*(x+1)-sum(1,x); } int main(){ cin>>n>>m; memset(c,0,sizeof(c)); ll now=0,x; for(int i=1;i<=n;i++){ cin>>x; a[i]=x-now; now=x; } for(int i=1;i<=n;i++){ add(0,i,a[i]);//差分陣列a[i] add(1,i,i*a[i]);//差分陣列i*a[i] } char ch; ll l,r,d; while(m--){ cin>>ch; if(ch=='C'){ cin>>l>>r>>d; add(0,l,d); add(0,r+1,-d); add(1,l,l*d); add(1,r+1,(r+1)*(-d)); } else { cin>>l>>r; cout<<(prefix_sum(r)-prefix_sum(l-1))<<endl; } } return 0; }
寫於:2020/8/26 17:27