P3157 [CQOI2011] 动态逆序对
这题竟然自己想出来了/jy/jy/jy(虽说挺裸的)。
考虑计算要被删除的数对于整个序列的贡献。
设要删除的数为下标为 \(x\),值为 \(a_x\),贡献为 \([1,x)\) 中大于 \(a_x\) 的数的个数加上 \((x,n]\) 中小于 \(a_x\) 的数个数。答案减去贡献,随后删除。
所以我们考虑树套树,需要的操作有:
-
单点修改。
-
区间查询大于或小于 \(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;
}