Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 6912 Solved: 2438
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删
除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
以下n行每行包含一个1到n之间的正整数,即初始排列。
以下m行每行一个正整数,依次为每次删除的元素。
N<=100000 M<=50000
输出包含m行,依次为删除每个元素之前,逆序对的个数。
5 4 1 5 3 4 2 5 1 4 2
5 2 2 1 样例解释 (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
这题已知有三种做法:
1、主席树+树状数组
2、树套树随便套
3、cdq分治
用cdq分治的话有一种非常巧妙的思路:先时间倒流,那么每次询问就转化成了求逆序对的个数
其实也不用。。
我们考虑一个数删除之后会对答案产生怎样的贡献
设当前删除了第$i$个元素,那么在$1 - i$中比它大的都要减去
在$(i + 1) - N$中比他小的都要减去
这样的话直接正着循环一遍再倒着循环一遍就行了。
用树状数组求逆序对
代码抄借鉴的candy大佬,写的非常妙
#include<cstdio>
#include<vector>
#include<algorithm>
#define LL long long
using namespace std;
const int MAXN = 400001, INF = 1e9 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9'){if(c == '-')f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
struct Query {
int t, x, val, type, id;
bool operator < (const Query &rhs) const {
return x == rhs.x ? val < rhs.val : x < rhs.x;
}
}Q[MAXN], Tp[MAXN];
int N, M, a[MAXN], pos[MAXN], tim;
LL ans[MAXN];
#define lb(x) (x & -x)
int T[MAXN];
void Add(int pos, int val) {for(int i = pos; i <= N; i += lb(i)) T[i] += val;}
int Sum(int pos) {int ans = 0; for(int i = pos; i >= 1; i -= lb(i)) ans += T[i]; return ans;}
void CDQ(int l, int r) {
if(l == r) return;
int mid = l + r >> 1;
for(int i = l; i <= r; i++)
if(Q[i].t <= mid) Add(Q[i].val, Q[i].type);
else ans[Q[i].id] += Q[i].type * (Sum(N) - Sum(Q[i].val));
for(int i = l; i <= r; i++) if(Q[i].t <= mid) Add(Q[i].val, -Q[i].type);
for(int i = r; i >= l; i--)
if(Q[i].t <= mid) Add(Q[i].val, Q[i].type);
else ans[Q[i].id] += Q[i].type * (Sum(Q[i].val - 1));
for(int i = l; i <= r; i++)if(Q[i].t <= mid) Add(Q[i].val, -Q[i].type);
int p1 = l, p2 = mid + 1;
for(int i = l; i <= r; i++)
if(Q[i].t <= mid) Tp[p1++] = Q[i];
else Tp[p2++] = Q[i];
for(int i = l; i <= r; i++) Q[i] = Tp[i];
CDQ(l, mid); CDQ(mid + 1, r);
}
int main() {
#ifdef WIN32
//freopen("a.in", "r", stdin);
#endif
N = read(); M = read();
for(int i = 1; i <= N; i++) {
a[i] = read(); pos[a[i]] = i ;
Q[++tim] = (Query) {tim, i, a[i], 1, 0};
}
for(int i = 1; i <= M; i++) {
int x = read();
Q[++tim] = (Query) {tim, pos[x], x, -1, i};
}
sort(Q + 1, Q + tim + 1);
CDQ(1, tim);
for(int i = 1; i <= M; i++) {
ans[i] += ans[i - 1];
printf("%lld\n", ans[i - 1]);
}
return 0;
}