[BZOJ 3295][CQOI2011]动态逆序对
又一道坑了很久没有写题解的……
删除操作特别的棘手,但好在我们可以离线~时光倒流之后,删除就变成了添加。
每个点加进来之后,对答案的贡献可以分为两部分:
- 加入比他早,位置在他前面,值比他大的点。
- 加入比他早,位置在他后面,值比他小的点。
然后两者都可以用CDQ统计(我还偷懒用同一个CDQ做的)。
代码:
/**************************************************************
Problem: 3295
User: danihao123
Language: C++
Result: Accepted
Time:2332 ms
Memory:5768 kb
****************************************************************/
#include <cstdio>
#include <stack>
#include <algorithm>
using std::stack;
using std::sort;
const int maxn = 100005;
typedef long long ll;
struct Query {
int id;
int p, v;
};
int n;
ll C[maxn];
int lowbit(int x) {
return x & (-x);
}
void add(int p, int v) {
while(p <= n) {
C[p] += v;
p += lowbit(p);
}
}
ll sum(int p) {
ll ret = 0;
while(p > 0) {
ret += C[p];
p -= lowbit(p);
}
return ret;
}
int query(int l, int r) {
return sum(r) - sum(l - 1);
}
void clean(int p) {
while(p <= n && C[p] != 0) {
C[p] = 0;
p += lowbit(p);
}
}
Query A[maxn], tmp[maxn];
ll ans[maxn];
void CDQ(int L, int R, bool flag) {
if(L == R) {
return;
}
int M = L + (R - L) / 2;
CDQ(L, M, flag); CDQ(M + 1, R, flag);
for(int p = L, l = L, r = M + 1; p <= R; p ++) {
if(r > R || (l <= M && (flag ? A[l].p < A[r].p : A[l].p > A[r].p))) {
tmp[p] = A[l];
add(A[l].v, 1);
l ++;
} else {
tmp[p] = A[r];
ans[A[r].id] += query(A[r].v + 1, n);
r ++;
}
}
for(int i = L; i <= M; i ++) {
clean(A[i].v);
}
for(int i = L; i <= R; i ++) {
A[i] = tmp[i];
}
}
bool cmp_id(const Query& a, const Query& b) {
return a.id < b.id;
}
int arr[maxn];
bool del[maxn];
int pos[maxn];
stack<int> delS;
int main() {
int m;
scanf("%d%d", &n, &m);
int id_siz = 0;
for(int i = 1; i <= n; i ++) {
scanf("%d", &arr[i]);
}
for(int i = 1; i <= m; i ++) {
int a;
scanf("%d", &a);
delS.push(a);
del[a] = true;
}
for(int i = 1; i <= n; i ++) {
if(del[arr[i]]) {
pos[arr[i]] = i;
} else {
id_siz ++;
A[id_siz].id = id_siz;
A[id_siz].p = i;
A[id_siz].v = arr[i];
}
}
while(!delS.empty()) {
int a = delS.top(); delS.pop();
id_siz ++;
A[id_siz].id = id_siz;
A[id_siz].p = pos[a];
A[id_siz].v = a;
}
CDQ(1, n, true);
sort(A + 1, A + 1 + n, cmp_id);
for(int i = 1; i <= n; i ++) {
A[i].v = n - A[i].v + 1;
}
CDQ(1, n, false);
for(int i = 1; i <= n; i ++) {
ans[i] += ans[i - 1];
}
for(int i = 0; i < m; i ++) {
printf("%lld\n", ans[n - i]);
}
return 0;
}