排队

我要自闭了。
感觉vjudge在歧视线段树套平衡树一介 民,反正是个TLE。以后再也不套这玩意儿了。(听说有人暴力归并在vjudge上AC了

其实我们发现,每次操作的逆序对只会在 ( a i − b i ) (ai-bi) (aibi)之间变化。那么我们其实只用计算ai的交换,bi的交换对答案的贡献。看看下面的🍐(将区间排序后的结果):

1 1 2 3 3

对于bi,我们增加的是第一个1与第一个3之间数的个数。
对于ai,我们增加的是最后一个1与最后一个3之间数的个数。

然后就可以算了。

上马!

#pragma GCC optimize(2)
#include<cstdio>
#include<cctype>
#include<cstdlib>
using namespace std;

const int N = 2 * 1e4 + 3, M = 1e7, mod = 1e9 + 7;

int h[N], z, p, q, res, t[N], val[M << 2], cnt, siz[M << 2], n, m, w[N], root[M << 2], rt, key[M << 2], son[M << 2][2];

int randd() {
	return (rand() * 6666) ^ rand();
}

inline int read() {
    int x = 0, f = 1;
    char s = getchar();
    while(! isdigit(s)) {
        if(s == '-')
            f = -1;
        s = getchar();
    }
    while(isdigit(s)) {
        x = (x << 1) + (x << 3) + (s ^ 48);
        s = getchar();
    }
    return x * f;
}

inline void print(int x) {
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}

void Swap(int &x, int &y) {
	int t = x;
	x = y;
	y = t;
}

inline void pushUp(const int o) {
	if(! o)
		return;
	siz[o] = siz[son[o][0]] + siz[son[o][1]] + 1;
	return;
}

inline int build(const int x) {
	val[++ cnt] = x;
	key[cnt] = randd() % mod;
	siz[cnt] = 1;
	return cnt;
}

void split(const int o, const int k, int &x, int &y) {
	if(! o)
		x = y = 0;
	else {
		if(val[o] <= k) {
			x = o;
			split(son[o][1], k, son[o][1], y);
		}
		else {
			y = o;
			split(son[o][0], k, x, son[o][0]);
		}
		pushUp(o);
	}
}

int merge(const int x, const int y) {
	if(! x || (! y))
		return x | y;
	if(key[x] < key[y]) {
		son[x][1] = merge(son[x][1], y);
		pushUp(x);
		return x;
	}
	else {
		son[y][0] = merge(x, son[y][0]);
		pushUp(y);
		return y;
	}
}

int create(const int l, const int r) {
	rt = 0;
	for(int i = l; i <= r; ++ i) {
		split(rt, w[i], p, q);
		rt = merge(merge(p, build(w[i])), q);
	}
	return rt;
}

void Build(const int o, const int l, const int r) {
	if(l > r)
		return;
	root[o] = create(l, r);
	if(l == r)
		return;
	int mid = l + r >> 1;
	Build(o << 1, l, mid);
	Build(o << 1 | 1, mid + 1, r);
}

void msort(const int l, const int r) {
	if(l == r)
		return;
	int mid = (l + r) >> 1;
	msort(l, mid);
	msort(mid + 1, r);
	int i = l, j = mid + 1, ans = 0, k = l;
	while(i <= mid && j <= r) {
		if(h[i] > h[j]) {
			res += mid - i + 1;
			t[k ++] = h[j ++];
		}
		else
			t[k ++] = h[i ++];
	}
	while(i <= mid)
		t[k ++] = h[i ++];
	while(j <= r)
		t[k ++] = h[j ++];
	for(int p = l; p <= r; ++ p)
		h[p] = t[p];
}

inline int del(int rt, const int pos, const int k) {
	split(rt, w[pos] - 1, p, q);
	split(q, w[pos], q, z);
	q = merge(son[q][0], son[q][1]);
	rt = merge(merge(p, q), z);
	split(rt, k, p, q);
	rt = merge(merge(p, build(k)), q);
	return rt;
}

void Delete(const int o, const int l, const int r, const int pos, const int k) {
	if(l > r || l > pos || r < pos)
		return;
	root[o] = del(root[o], pos, k);
	if(l == r)
		return;
	int mid = l + r >> 1;
	Delete(o << 1, l, mid, pos, k);
	Delete(o << 1 | 1, mid + 1, r, pos, k);
}

int rank(const int o, const int k) {
	split(o, k - 1, p, q);
	int ans = siz[p] + 1;
	merge(p, q);
	return ans;
}

int askRank(const int o, const int l, const int r, const int L, const int R, const int k) {
	if(l > R || r < L)
		return 0;
	if(l >= L && r <= R)
		return rank(root[o], k) - 1;
	int mid = l + r >> 1;
	return askRank(o << 1, l, mid, L, R, k) + askRank(o << 1 | 1, mid + 1, r, L, R, k);
}

int main() {
	int a, b, c, d, tmp;
	n = read();
	for(int i = 1; i <= n; ++ i) {
		w[i] = read();
	}
	Build(1, 1, n);
	for(int i = 1; i <= n; ++ i)
		h[i] = w[i];
	msort(1, n);
	print(res);
	putchar('\n');
	m = read();
	for(int i = 1; i <= m; ++ i) {
		c = read();
		d = read();
		if(w[c] == w[d]) {
			print(res);
			putchar('\n');
			continue;
		}
		if(c > d)
			Swap(c, d);
		if(w[c] < w[d]) {
			a = askRank(1, 1, n, c, d, w[c]);
			b = askRank(1, 1, n, c, d, w[d]);
			tmp = (b - a) * 2 - askRank(1, 1, n, c, d, w[c] + 1) + a + askRank(1, 1, n, c, d, w[d] + 1) - b - 1;
			res += tmp;
		}
		else {
			a = askRank(1, 1, n, c, d, w[c]);
			b = askRank(1, 1, n, c, d, w[d]);
			tmp = (a - b) * 2 - askRank(1, 1, n, c, d, w[d] + 1) + b + askRank(1, 1, n, c, d, w[c] + 1) - a - 1;
			res -= tmp;
		}
		print(res);
		putchar('\n');
		Delete(1, 1, n, c, w[d]);
		Delete(1, 1, n, d, w[c]);
		Swap(w[c], w[d]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值