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;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值