题意:有150000个数,10000条操作,每次将第i个数变为x,讯问每次操作后逆序对的数目。
解法1:树状数组+treap,树状数组的每个元素都是一棵树,这样可以在lognlogn时间内查询前i项有多少个小于等于k的元素,当某个元素法师改变时,只需从树状数组中对应的treap中进行元素的删减,每次修改前后统计的第i个元素形成的逆序对数,便可知每次操作后逆序对的数目。由于Treap常熟很大,因此虽然复杂度不高但是效率很低
解法2:Sqrt(N)分块+排序,统计前i项小于k的元素个数,类似于spoj3261http://www.spoj.pl/problems/RACETIME/;其他操作类似于解法1,代码量少,常数小,效率较高。
#include <cstdio> #include <algorithm> #include<cmath> using namespace std; const int maxn = 250010; const int maxm=510; struct Block { int num[maxm], arr[maxm], len; bool dirty; void init(int n) { len = n; dirty = true; } int get(int k) { if (dirty) { for (int i = 1; i <= len; i++) arr[i] = num[i]; sort(arr + 1, arr + len + 1); dirty = false; } int left = 1, right = len, ans = 0; while (left <= right) { int mid = (left + right) >> 1; if (arr[mid] <= k) { ans = mid; left = mid + 1; } else right = mid - 1; } return ans; } void update(int i, int v) { if (v == num[i]) return; num[i] = v; dirty = true; } int query(int left, int right, int v) { int sum = 0; for (int i = left; i <= right; i++) if (num[i] <= v) { sum++; } return sum; } } bk[maxm]; struct IndexTree { int ss[50020]; const static int N = 50010; void init() { for (int i = 1; i <= N; i++) ss[i] = 0; } int lowbit(int k) { return (k & -k); } void inc(int i, int v) { while (i <= N) { ss[i] += v; i += lowbit(i); } } int get(int i) { int res = 0; while (i > 0) { res += ss[i]; i -= lowbit(i); } return res; } } all; int belong[maxn], id[maxn], M, n,m,x,y; int arr[maxn]; void build() { for (int i = 1; i * i <= n; i++) M = i; int cnt = 0, len = M; for (int i = 1; i <= n; i++) { if (len == M) { bk[++cnt].init(M); len = 0; } belong[i] = cnt; id[i] = ++len; bk[cnt].num[len] = arr[i]; } bk[cnt].len = len; } int query(int k, int c) { int sum = 0; int b = belong[k]; for (int i = 1; i < b; i++) sum += bk[i].get(c); sum += bk[b].query(1, id[k], c); return sum; } long long res; void init() { res = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", arr + i); res += i - 1 - all.get(arr[i]); all.inc(arr[i], 1); } } int cal(int k) {// 计算第k项元素形成的逆数对个数 int a = all.get(arr[k] - 1); int b = query(k, arr[k] - 1); int c = query(k, arr[k]); return a - b + k - c; } int main() { init(); build(); scanf("%d", &m); while (m--) { scanf("%d%d", &x, &y); res -= cal(x); all.inc(arr[x], -1); all.inc(y, 1); int cnt = belong[x]; bk[cnt].update(id[x], y); arr[x] = y; res += cal(x); printf("%lld\n", res); } return 0; }
Uva11990 "Dynamic'' Inversion(Rujia Liu's Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University,Problem D)
这题M较大,因此使用第一种方法比第二种效率要高。
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include<cmath> #include<map> using namespace std; const int maxn = 200010; const int inf = 1 << 30; struct TreeNode { int key, pri; int left, right, size, num; void init() { left = right = 0; num = size = 1; pri = rand(); } }; TreeNode nodes[maxn * 25]; int stack[maxn*25], top, cnt; int newnode() { int ret; if (top) ret = stack[--top]; else ret = ++cnt; nodes[ret].init(); return ret; } struct Treap { int root; void init() { root = cnt = top = 0; nodes[0].pri = -0x7FFFFFFF; } void push_up(int idx) { nodes[idx].size = nodes[nodes[idx].left].size + nodes[nodes[idx].right].size + nodes[idx].num; } void leftRotate(int &root) { int tmp = nodes[root].right; nodes[root].right = nodes[nodes[root].right].left; nodes[tmp].left = root; push_up(root); push_up(tmp); root = tmp; } void rightRotate(int &root) { int tmp = nodes[root].left; nodes[root].left = nodes[nodes[root].left].right; nodes[tmp].right = root; push_up(root); push_up(tmp); root = tmp; } void insert(int k) { insert(k, root); } void insert(int k, int& root) { if (nodes[root].key == k) { nodes[root].num++; nodes[root].size++; return; } if (!root) { root = newnode(); nodes[root].key = k; return; } if (k < nodes[root].key) { insert(k, nodes[root].left); if (nodes[nodes[root].left].pri > nodes[root].pri) rightRotate(root); } else { insert(k, nodes[root].right); if (nodes[nodes[root].right].pri > nodes[root].pri) leftRotate(root); } push_up(root); } void del(int k) { del(root, k); } void del(int &root, int k) { if (nodes[root].key == k) { if (!nodes[root].left && !nodes[root].right) { if (nodes[root].num == 1) { stack[top++] = root; root = 0; } else { nodes[root].num--; nodes[root].size--; } return; } if (nodes[nodes[root].left].pri > nodes[nodes[root].right].pri) { rightRotate(root); del(nodes[root].right, k); } else { leftRotate(root); del(nodes[root].left, k); } push_up(root); return; } if (k < nodes[root].key) del(nodes[root].left, k); else del(nodes[root].right, k); push_up(root); } int find(int k) { return find(root, k); } int find(int root, int k) { if (root == 0) return 0; if (nodes[root].key == k) return nodes[nodes[root].left].size + nodes[root].num; if (nodes[root].key > k) return find(nodes[root].left, k); else return nodes[nodes[root].left].size + nodes[root].num + find( nodes[root].right, k); } } tree; int lowbit(int k) { return (k & -k); } struct node { int len; Treap tree; void init() { tree.init(); } int get(int k) { return tree.find(k); } void update(int v) { if (v > 0) tree.insert(v); else tree.del(-v); } }; struct IndexTree { int ss[maxn],N; void init(int n) { N=n; memset(ss, 0, sizeof(ss)); } void inc(int i, int v) { while (i <= N) { ss[i] += v; i += lowbit(i); } } int get(int i) { int res = 0; while (i > 0) { res += ss[i]; i -= lowbit(i); } return res; } }; node ss[maxn]; int pos[maxn], arr[maxn], m, n, x; IndexTree all, now; long long res; void init() { now.init(n); all.init(n); for (int i = 1; i <= n; i++) ss[i].init(); } void update(int i, int v) { while (i <= n) { ss[i].update(v); i += lowbit(i); } } int query(int i, int v) { int res = 0; while (i > 0) { res += ss[i].get(v); i -= lowbit(i); } return res; } void build() { res = 0; for (int i = 1; i <= n; i++) { scanf("%d", &x); pos[x] = i; arr[i] = x; res += i - 1 - all.get(x); all.inc(x, 1); update(i, x); now.inc(i, 1); } } int cal(int k) { int a = all.get(arr[k] - 1); int b = query(k, arr[k] - 1); k = now.get(k); return a - b + k-b-1; } int main() { while (scanf("%d %d", &n, &m) != EOF) { init(); build(); while (m--) { printf("%lld\n",res); scanf("%d", &x); res -= cal(pos[x]); all.inc(x, -1); now.inc(pos[x], -1); update(pos[x], -x); } } return 0; }