P3157 [CQOI2011] 动态逆序对

P3157 [CQOI2011] 动态逆序对

这题竟然自己想出来了/jy/jy/jy(虽说挺裸的)。

考虑计算要被删除的数对于整个序列的贡献。

设要删除的数为下标为 \(x\),值为 \(a_x\),贡献为 \([1,x)\) 中大于 \(a_x\) 的数的个数加上 \((x,n]\) 中小于 \(a_x\) 的数个数。答案减去贡献,随后删除。

所以我们考虑树套树,需要的操作有:

  1. 单点修改。

  2. 区间查询大于或小于 \(x\) 的数的个数。

代码稍后贴。


怎么还有点卡常 qwq

code:

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define ll long long
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') f = c == '-' ? -1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x<<3)+(x<<1)+(c^48), c = getchar();
	return x*f;
}

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

mt19937 rnd(time(0));
const int N = 1e5+5, M = N*20, inf = 0x7fffffff;
int n, m, a[N], c[N], pos[N];
ll ans;

void add(int x) { for (; x <= n; x += x&-x) ++c[x]; }

int ask(int x) { int res = 0; for (; x; x -= x&-x) res += c[x]; return res; }

int x, y, z, cnt, key[M], dat[M], siz[M], son[M][2];

int newnode(int v) {
	siz[++cnt] = 1, key[cnt] = v, dat[cnt] = rnd();
	return cnt;
}

void pushup(int x) { siz[x] = siz[son[x][0]]+siz[son[x][1]]+1; }

void split(int now, int k, int &x, int &y) {
	if (!now) return (void)(x = y = 0);
	if (key[now] <= k) x = now, split(son[x][1], k, son[x][1], y);
	else y = now, split(son[y][0], k, x, son[y][0]);
	pushup(now);
}

int merge(int x, int y) {
	if (!x || !y) return x+y;
	if (dat[x] > dat[y]) return son[x][1] = merge(son[x][1], y), pushup(x), x;
	else return son[y][0] = merge(x, son[y][0]), pushup(y), y;
}

void ins(int &rt, int v) {
	split(rt, v, x, y);
	rt = merge(merge(x, newnode(v)), y);
}

void del(int &rt, int v) {
	split(rt, v, x, z);
	split(x, v-1, x, y);
	y = merge(son[y][0], son[y][1]);
	rt = merge(merge(x, y), z);
}

int mx(int rt, int v) {
	split(rt, v, x, y);
	int tmp = siz[y];
	return rt = merge(x, y), tmp;
}

int mn(int rt, int v) {
	split(rt, v-1, x, y);
	int tmp = siz[x];
	return rt = merge(x, y), tmp;
}

#define ls p<<1
#define rs p<<1|1
int rt[N<<2];

void build(int p, int l, int r) {
	for (int i = l; i <= r; ++i) ins(rt[p], a[i]);
	if (l == r) return;
	int mid = l+r>>1;
	build(ls, l, mid), build(rs, mid+1, r);
}

void modify(int p, int l, int r, int x) {
	del(rt[p], a[x]);
	if (l == r) return;
	int mid = l+r>>1;
	x <= mid ? modify(ls, l, mid, x) : modify(rs, mid+1, r, x);
}

int que_mx(int p, int l, int r, int ql, int qr, int x) {
	if (qr < l || r < ql) return 0;
	if (ql <= l && r <= qr) return mx(rt[p], x);
	int mid = l+r>>1;
	return que_mx(ls, l, mid, ql, qr, x)+que_mx(rs, mid+1, r, ql, qr, x);
}

int que_mn(int p, int l, int r, int ql, int qr, int x) {
	if (qr < l || r < ql) return 0;
	if (ql <= l && r <= qr) return mn(rt[p], x);
	int mid = l+r>>1;
	return que_mn(ls, l, mid, ql, qr, x)+que_mn(rs, mid+1, r, ql, qr, x);
}

int main() {
	n = read(), m = read();
	for (int i = 1; i <= n; ++i) {
		a[i] = read(), pos[a[i]] = i;
		ans += i-1-ask(a[i]), add(a[i]);
	}
	build(1, 1, n);
	while (m--) {
		int x = read();
		write(ans), enter;
		ans -= que_mx(1, 1, n, 1, pos[x]-1, x)+que_mn(1, 1, n, pos[x]+1, n, x);
		modify(1, 1, n, pos[x]);
	}
	return 0;
}
posted @ 2024-01-12 13:57  123wwm  阅读(21)  评论(0)    收藏  举报