樹狀數組用於求區間和,其修改和查詢的複雜度都是\(O(logn)\),很是好寫,比較小巧。node
幾種基礎用法,關於權值樹狀數組在另外一篇博客。c++
#include <bits/stdc++.h> #define N 50005 using namespace std; typedef long long ll; int max(int a, int b) { return a > b ? a : b; } int min(int a, int b) { return a < b ? a : b; } int d[N]; int n; void update(int x, int v) { for (int i = x; i <= n; i += i & (-i)) d[i] += v; } ll query(int x) { ll ans = 0; for (int i = x; i; i -= i & (-i)) ans += d[i]; return ans; } int main() { int t; scanf("%d", &t); int cnt = 0; while (t--) { memset(d, 0, sizeof(d)); scanf("%d", &n); for (int i = 1; i <= n; i++) { int v; scanf("%d", &v); update(i, v); } cnt++; printf("Case %d:\n", cnt); while (1) { char ch[10]; scanf("%s", ch); int x, y; if (ch[0] == 'Q') { scanf("%d%d", &x, &y); printf("%lld\n", query(y) - query(x - 1)); } else if (ch[0] == 'A') { scanf("%d%d", &x, &y); update(x, y); } else if (ch[0] == 'S') { scanf("%d%d", &x, &y); update(x, -y); } else break; } } return 0; }
不建議使用樹狀數組求區間最小值,比較難以理解,並且寫起來並不簡單git
#include <cstdio> #include <cstring> #define N 200050 using namespace std; int h[N], a[N]; int lowbit(int x) { return x & (-x); } int n, m; int max(int a, int b) {return a > b ? a : b;} void update(int x) { int lx; while (x <= n) { h[x] = a[x]; lx = lowbit(x); for (int i = 1; i < lx; i <<= 1) h[x] = max(h[x], h[x - i]); x += lowbit(x); } } int query(int l, int r) { int ans = 0; while (r >= l) { ans = max(a[r], ans); r--; for (; r - lowbit(r) >= l; r -= lowbit(r)) ans = max(h[r], ans); } return ans; } int main() { while (scanf("%d%d", &n, &m) != EOF) { memset(h, 0, sizeof(h)); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); update(i); } while (m--) { char ch[2]; int x, y; scanf("%s%d%d", ch, &x, &y); if (ch[0] == 'Q') { printf("%d\n", query(x, y)); } else { a[x] = y; update(x); } } } return 0; }
直接使用二維樹狀數組便可。數組
附:矩陣前綴和求一部分和的公式:spa
\(sumv(x2, y2) - sumv(x1 - 1, y2) - sumv(x2, y11 - 1) + sumv(x1 - 1, y11 - 1)\)code
\(sumv(x,y)\)爲從(1,1)到(x,y)的前綴和排序
#include <cstdio> #include <cstring> #define p 1000000007 #define N 1050 using namespace std; typedef long long ll; ll d[N][N]; int n, m; int lowbit(int x) { return x & (-x); } void update(int x, int y, ll v) { for (int i = x; i <= n; i += lowbit(i)) { for (int j = y; j <= n; j += lowbit(j)) { d[i][j] += v; } } } ll sumv(int x, int y) { ll ans = 0; for (int i = x; i; i -= lowbit(i)) { for (int j = y; j; j -= lowbit(j)) { ans += d[i][j]; } } return ans; } ll query(int x1, int y11, int x2, int y2) { return sumv(x2, y2) - sumv(x1 - 1, y2) - sumv(x2, y11 - 1) + sumv(x1 - 1, y11 - 1); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { char ch[10]; scanf("%s", ch); if (ch[0] == 'A') { int x, y; ll v; scanf("%d%d%lld", &x, &y, &v); x++; y++; update(x, y, v); } else { int x1, y11, x2, y2; scanf("%d%d%d%d", &x1, &y11, &x2, &y2); x1++; y11++; x2++; y2++; printf("%lld\n", (query(x1, y11, x2, y2) + p) % p); } } return 0; }
使用樹狀數組維護一個位置以前一共有了多少數,當第i個數a[i]加進來時,先update更新,在詢問這個數以前一共有了多少數,使用i-get(a[i])即爲對逆序對的貢獻,累計便可get
此題題意是讓a數組和b數組之間每一個位置均對應爲相同的大小順序,問最少須要移動幾回,即把a的位置移動到b的位置須要移動多少次,排序以後將a映射到b求逆序對便可博客
#include<bits/stdc++.h> #define maxn 100060 #define p 99999997 using namespace std; int c[maxn], d[maxn], n; inline int getnum(){ char c; int ans = 0; bool flag = false; while (!isdigit(c = getchar()) && c != '-'); if (c == '-') flag = true; else ans = c - '0'; while (isdigit(c = getchar())) ans = ans * 10 + c - '0'; return ans * (flag ? -1 : 1); } struct node{ long long v; int pos; }a[maxn], b[maxn]; int cmp(node x, node y){ return x.v < y.v; } inline int lowbit(int x){ return x & (-x); } inline void updata(int x){ while (x <= n){ d[x]++; x += lowbit(x); } } inline int getsum(int x){ int ans = 0; while (x > 0){ ans += d[x] % p; x -= lowbit(x); } return ans; } int main(){ n = getnum(); for (int i = 1; i <= n; i++){ a[i].v = getnum(); a[i].pos = i; } for (int i = 1; i <= n; i++){ b[i].v = getnum(); b[i].pos = i; } sort(a + 1, a + n + 1, cmp); sort(b + 1, b + n + 1, cmp); for (int i = 1; i <= n; i++){ c[b[i].pos] = a[i].pos; } int ans = 0; for (int i = 1; i <= n; i++){ updata(c[i]); ans += i - getsum(c[i]); ans %= p; } printf("%d", ans); return 0; }