树状数组模板
1:树状数组求和模板
给n:个数a1,a2,a3,…,an。
支持q个操作:
-
1 x d
,修改ax=d。 -
2 x
,查询∑xi=1ai。
输入格式
第一行两个整数n,q(1≤n,q≤2×105)。
接下来一行n个整数a1,a2,…,an(1≤ai≤109)。
接下来q行,每行一个形如1 x d
或者2 x
的操作,保证1≤x≤n,1≤d≤1e9。
输出格式
对于每个查询,输出一行,表示答案。
样例输入
5 5
1 2 3 4 5
2 4
1 1 5
2 5
1 2 3
2 3
样例输出
10
19
11

#include <bits/stdc++.h> using namespace std; typedef long long ll; int n,m; ll a[300000],c[300000]; int lowbit(ll x) { return x&(-x); } void updata(int l_,ll r_) { while(l_ <= n) { c[l_] += r_; l_ += lowbit(l_); } } void query(int l_) { ll ans = 0; while(l_ > 0) { ans += c[l_]; l_ -= lowbit(l_); } cout << ans << '\n'; } void solve() { //int n,m; cin >> n >> m; for(int i = 1;i <= n;i ++) { cin >> a[i]; updata(i,a[i]); } while(m--) { int op; cin >> op; if(op == 1) { int l; ll r; cin >> l >> r; updata(l,r-a[l]); a[l] = r; } else { int l; cin >> l; query(l); } } } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; t = 1; //cin >> t; while(t--) { solve(); } }
2:树状数组求逆序对模板
有 n 个数 a1,a2,…,an,对于其中的两个数字 x,y,如果满足 x 出现的位置在 y 出现的位置前面并且 x 比 y 大,则称 (x,y)为数组 a 的一个逆序对。请问数组 a 的逆序对一共有多少个?形式化的说,请求出有多少组 (i,j)满足 i<j并且 ai>aj。
输入格式
第一行一个整数 n。
接下来一行 n 个整数,a1,a2,…,an。
输出格式
一行一个数,表示答案。
样例输入
4
4 2 3 1
样例输出
5
样例解释
5 个逆序对分别为 (4,2),(4,3),(4,1),(2,1),(3,1)。
数据范围
对于 100%100% 的数据,保证 2≤n≤100000,1≤ai≤n 并且每个数字都只会出现一次。

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e5; int n; ll a[N],d[N]; int lowbit(int x) { return x&(-x); } void updata(ll l,int r) { while(l <= n) { d[l] += r; l += lowbit(l); } } int query(ll l) { ll sum = 0; while(l) { sum += d[l]; l -= lowbit(l); } return sum ; } void solve() { cin >> n; for(int i = 1;i <= n;i ++) { cin >> a[i]; a[i] = n - a[i] + 1; } ll ans = 0; for(int i = 1;i <= n;i ++) { ans += query(a[i]); updata(a[i],1); } cout << ans << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; t = 1; while(t--) { solve(); } }
3:树状数组二分模板
给n 个数a1,a2,a3,…,an。
支持q个操作:
-
1 x d
,修改ax=d。 -
2 s
,查询最大的T(0≤T≤n)满足∑Ti=1ai≤s。
输入格式
第一行两个整数n,q(1≤n,q≤2×1e5)。
接下来一行n个整数a1,a2,…,an(1≤ai≤1e9)。
接下来q行,每行一个形如1 x d
或者2 s
的操作,保证1≤x≤n,1≤d≤1e9,1≤s≤1e14。
输出格式
对于每个查询,输出一行,表示答案。
样例输入
5 5
1 2 3 4 5
2 6
2 5
1 1 100
2 10
2 1000
样例输出
3 2 0 5

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e6; int n,m; ll a[N],c[N]; ll lowbit(ll x) { return x&(-x); } void updata(ll x,ll y) { while(x<=n) { c[x] += y; x += lowbit(x); } } ll query(ll x) { ll ans = 0; for(int j = 18;j >= 0;j--) { if(ans + (1 << j) <= n && c[ans + (1 << j)] <= x) { ans += (1<<j); x -= c[ans]; } } return ans; } void solve() { cin >> n >> m; for(int i = 1;i <= n;i ++) { cin >> a[i]; updata(i,a[i]); } while(m--) { ll op; cin >> op; if(op == 1) { ll x,y; cin >> x >> y; updata(x,y-a[x]); a[x] = y; } else { ll x; cin >> x; ll ans = query(x); cout << ans << '\n'; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; t = 1; while(t--) { solve(); } }
4:二维树状数组模板
给n×m个数a1,1,a1,2,a1,3,…,a1,m,…,an,m。
支持q个操作:
-
1 x y d
,修改ax,y=d。 -
2 x y
,查询∑xi=1∑yj=1ai,j。
输入格式
第一行三个整数n,m,q(1≤n,m≤500,q≤2×1e5)。
接下来n行每行m个整数a1,1,a1,2,…,a1,m,…,an,m(1≤ai,j≤109)。
接下来q行,每行一个形如1 x y d
或者2 x y
的操作,保证1≤x≤n,1≤y≤m,1≤d≤1e9。
输出格式
对于每个查询,输出一行,表示答案。
样例输入
2 3 5
1 1 4
5 1 4
2 2 3
1 1 1 4
2 1 3
1 2 3 10
2 2 3
样例输出
16
9
25

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e3; int n,m,q; ll a[N][N],c[N][N]; ll lowbit(ll x) { return x&(-x); } void updata(ll x,ll y,ll z) { ll w = y; while(x<=n) { y = w; while(y<=m) { c[x][y] += z; y += lowbit(y); } x += lowbit(x); } } ll query(ll x,ll y) { ll ans = 0,w = y; while(x) { y = w; while(y) ans += c[x][y],y -= lowbit(y); x -= lowbit(x); } return ans; } void solve() { cin >> n >> m >> q; for(int i = 1;i <= n;i ++) { for(int j = 1;j <= m;j ++) cin >> a[i][j],updata(i,j,a[i][j]); } while(q--) { ll op; cin >> op; if(op == 2) { ll x,y; cin >> x >> y; ll ans = query(x,y); cout << ans << '\n'; } else { ll x,y,z; cin >> x >> y >> z; updata(x,y,z-a[x][y]); a[x][y] = z; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; t = 1; while(t--) { solve(); } }