spoj 861 SWAPS & uva 11990 "Dynamic'' Inversion(动态维护逆序对)

来源:互联网 发布:淘宝聚星台 编辑:程序博客网 时间:2024/06/05 00:55

题意:有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;} elseright = 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];elseret = ++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);elsedel(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);elsereturn 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);elsetree.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;}





原创粉丝点击