题目描述
Description
对于序列A,它的逆序对数定义为满足i<j,且AAi>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
Hint
样例解释
(1,5,3,4,2)>>(1,3,4,2)>>(3,4,2)>>(3,2)>>(3)。
数据范围
编号 1-2 3-4 5-6 7-8 9-10
n <=1000 <=30000 <=50000 <=60000 <=100000
m <=100 <=10000 <=20000 <=40000 <=50000
题目分析
首先我们可以发现对于每一个插入操作我们可以看作(t,x,y)的三元组也就是时间、位置、数值,只有当对于两个组出现t0<t,x0<x,y0>y或者t0<t,x0>x,y0<y的数对的数量,那么我们可以使用CDQ分治来搞一搞。首先可以发现我们的t,x,y每一个t都不存在另一个t’=t那么因为我们要保证的是每一个t0<t那么我们将t作为划分的关键字,在归并排序之前我们先将x作为排序的关键字,那么在划分之后我们可以保证划分后的左边和右边的x仍保持升序,同时保证左边的所有t都小于右边的,那么我们对于右边的每一个只需要找左边的所有的x比它小的元素的个数就可以保证但是因为这里我们还有第三个条件,那么我们使用树状数组将第三个元素作为前缀和保存下来,就可以从当前的所有满足前两个条件的数量中,减去不满足第三个条件的就可以完成题目,这里感谢azui大神的帮助
http://blog.csdn.net/u011542204/article/details/50571409
代码
#include
#include
#include
#include
using namespace std;
const int MAXN = 100000;
const int MAXM = 50000;
long long Tree[MAXN+10], up[MAXN+10];
int vtopos[MAXN+10], A[MAXN+10], n, m, time, Del[MAXM+10];
struct Pair{
int a, b, c;
Pair():a(0),b(0),c(0){}
Pair(int _a, int _b, int _c):a(_a),b(_b),c(_c){}
}Tasks[MAXN+10], tmp[MAXN+10];
int lowbit(int u){return (u&(-u));}
void add(int u, int v){
for(;u<=n;u+=lowbit(u)) Tree[u]+=1LL * v;
}
long long que(int u){
long long ret = 0;
for(;u;u-=lowbit(u)) ret += Tree[u];
return ret;
}
void make_task(int k){
int pos = vtopos[k];
++time;
Tasks[time] = Pair(time, pos, k);
}
void cdq(int L, int R){
if(R - L <= 0) return ;
int mid = (L + R) >> 1;
int l = L, r = mid+1, Len = R-L+1;
for(int i=0;iif(Tasks[i+L].a <= mid) tmp[l++] = Tasks[i+L];
else tmp[r++] = Tasks[i+L];
}
for(int i=L; i<=R; i++) Tasks[i] = tmp[i];
l = L;
for(int i=mid+1; i<=R; i++){
for(;l<=mid&&Tasks[i].b > Tasks[l].b;l++) add(Tasks[l].c, 1);
up[Tasks[i].a] += l-L-que(Tasks[i].c);
}
l--;
for(;l>=L;l--) add(Tasks[l].c, -1);
l = mid;
for(int i=R; i>mid; i--){
for(;l>=L&&Tasks[l].b>Tasks[i].b;l--) add(Tasks[l].c, 1);
up[Tasks[i].a] += que(Tasks[i].c);
}
l++;
for(;l<=mid;l++) add(Tasks[l].c, -1);
cdq(L, mid); cdq(mid+1, R);
}
bool cmp(Pair a, Pair b){return a.b < b.b;}
int main(){
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++){
scanf("%d", &A[i]);
vtopos[A[i]] = i;
}
for(int i=1;i<=m;i++) scanf("%d", &Del[i]);
for(int i=m;i>=1;i--) A[vtopos[Del[i]]] = -1;
for(int i=1;i<=n;i++) if(A[i] != -1) make_task(A[i]);
for(int i=m;i>=1;i--) make_task(Del[i]);
sort(Tasks+1, Tasks+1+n, cmp);
cdq(1, n);
for(int i=2;i<=n;i++) up[i] += up[i-1];
for(int i=1;i<=m;i++) printf("%I64d\n", up[n-i+1]);
return 0;
}