spoj 861 SWAPS & uva 11990 "Dynamic'' Inversion(動態維護逆序對)

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





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章