我要自闭了。
感觉vjudge在歧视线段树套平衡树一介贫 民,反正是个TLE。以后再也不套这玩意儿了。(听说有人暴力归并在vjudge上AC了 )
其实我们发现,每次操作的逆序对只会在 ( a i − b i ) (ai-bi) (ai−bi)之间变化。那么我们其实只用计算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;
}