初识树状数组,确实是一种优美的数据结构,夹杂着很强的数学模型在里面。
http://poj.org/summerschool/1_interval_tree.pdf 这里已经说明的非常清楚。
http://dongxicheng.org/structure/binary_indexed_tree/ 这篇文章说的也是差不多的。
重要的是去思考,为什么树形数组能够行的通,看了下面不难理解:
C1=A1
C2=A1+A2
C3=A3
C4=A1+A2+A3+A4
C5=A5
C6=A5+A6
C7=A7
C8=A1+A2+A3+A4+A5+A6+A7+A8
…………
C16=A1+A2+A3+A4+A5+A6+A7+A8+A9+A10+A11+A12+A13+A14+A15+A16
关于这一题,是求第k大数字,树形数组的O(logn)^2算法(还可以再优化到O(logn)),可谓把它的优美程度完美体现
#include <cstdio> #include <cstdlib> #include <cstring> const int MAXN = 200010; // c[i]树形数组,生成c[i]的数组s[i]表示,大小为i的的集合的个数 // f[i]节点i的父亲节点 // a[i]以节点i为根节点的集合元素个数,初始化为1 int c[MAXN], f[MAXN], a[MAXN]; int n, m; int find_set(int x) { int r = x; while (r != f[r]) r = f[r]; int p = x; while (p != r) { p = f[p]; f[p] = r; } return r; } inline int low_bit(int x) { return x & (-x); } void add(int p, int d) { for (int i = p; i <= n; i += low_bit(i)) c[i] += d; } int sum(int p) { int ans = 0; for (int i = p; i > 0; i -= low_bit(i)) ans += c[i]; return ans; } int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; ++i) c[i] = 0, a[i] = 1, f[i] = i; add(1, n); int num = n; for (int i = 1; i <= m; ++i) { int temp; scanf("%d", &temp); if (!temp) { int x, y; scanf("%d %d", &x, &y); x = find_set(x); y = find_set(y); if (x == y) continue; add(a[x], -1); add(a[y], -1); add(a[x] + a[y], 1); f[x] = y; a[y] += a[x]; --num; } else { int k; scanf("%d", &k); k = num - k + 1; int l = 1, r = n; while (l <= r) { int mid = (l + r) >> 1; if (k <= sum(mid)) r = mid - 1; else l = mid + 1; } printf("%d\n", l); } } return 0; }