# 前綴和/差分 如果把差分和前綴和視為對序列的操作,那麼差分和前綴和是一對互逆的操作: 對a數列進行差分可以得到d數列 對d數列做前綴和可以得到a數列。 同理: 對s數列進行差分可以得到a數列 對a數列做前綴和可以得到s數列。 差分數列d: $d_i=a_i-a_{i-1};d_1=a_1$ 前缀和數列s: $s_i=\sum_{i}^{j=1} a_j$ 用一個具體的例子說明 ``` a=[1,5,3,4,2](原始數列) =>d=[1,4,-2,1,-2](差分數列) =>s=[1,6,9,13,15](前缀和數列) ``` 小模板(不一定要這樣寫) ```cpp= int a[N+1],d[N+1],s[N+1]; for(int i=1;i<=N;i++){ d[i]=a[i]-a[i-1]; } for(int i=1;i<=N;i++){ s[i]=s[i-1]+a[i]; } ``` ### 前綴和範例 e346: 區間和練習 https://zerojudge.tw/ShowProblem?problemid=e346 ```cpp= #include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' #define inf 2e18 #define maxn 200005 #define mod 1000000007 signed main(){ ios::sync_with_stdio(0); cin.tie(0); int n; cin>>n; int arr[maxn]; arr[0]=0; for(int i=1;i<=n;i++){ cin>>arr[i]; arr[i]+=arr[i-1]; } int q; cin>>q; while(q--){ int l,r; cin>>l>>r; cout<<arr[r]-arr[l-1]<<endl; } } ``` codeforces:H1. 區間求和問題 (Range Sum Queries)【One-dimensional Version】 https://codeforces.com/group/H0qY3QmnOW/contest/383582/problem/H1 ```cpp= #include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' #define inf 2e18 #define maxn 200005 #define mod 1000000007 signed main(){ ios::sync_with_stdio(0); cin.tie(0); int n; cin>>n; int arr[maxn]; arr[0]=0; int sum=0; for(int i=1;i<=n;i++){ int k; cin>>k; sum+=k; arr[i]=sum; } int q; cin>>q; while(q--){ int a,b; cin>>a>>b; cout<<arr[b]-arr[a-1]<<endl;; } } ``` ### 差分範例 洛谷:P2367 语文成绩 https://www.luogu.com.cn/problem/P2367 因為要在vec上做單點修改 所以先把vec做差分 最後再還原去求最小值 ```cpp= #include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' #define inf 2e18 #define maxn 100005 #define mod 1000000007 signed main(){ ios::sync_with_stdio(0); cin.tie(0); int n,p; cin>>n>>p; vector<int>vec(n+2); for(int i=1;i<=n;i++){ cin>>vec[i]; } for(int i=n;i>=1;i--){ vec[i]=vec[i]-vec[i-1]; } while(p--){ int l,r,v; cin>>l>>r>>v; vec[l]+=v; vec[r+1]-=v; } int ans=1e9; for(int i=1;i<=n;i++){ vec[i]+=vec[i-1]; ans=min(ans,vec[i]); } cout<<ans; } ```