題意:有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;
}