Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。
给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
以下n行每行包含一个1到n之间的正整数,即初始排列。
以下m行每行一个正整数,依次为每次删除的元素。
N<=100000 M<=50000
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
题解Here!
据说正解是cdq分治?本蒟蒻并不会。。。
于是想起了这题:P1774 最接近神的人_NOI导刊2010提高(02)
那题是静态的逆序对,而这题要支持删除操作。
静态逆序对用了什么?树状数组!
树状数组维护什么?前缀和!
动态前缀和怎么维护?主席树!
于是一个树状数组套主席树就这么被YY构造出来了。。。
删除第一个前的逆序对自然能求出来.
此时我们考虑删除第一个元素,减少的逆序对个数就是在它前面的比他大的和在它后面比它小的,于是我们开两个数组来存:
sum_one[i] 表示的就是在i前面而且大于i位置上的元素的元素的个数。
sum_two[i] 表示的就是在i后面而且小于i位置上的元素的元素的个数。
sum_one[i] 就可以在读入的时候直接处理一下。
sum_two[i] 可以反向添加然后处理出来。
但是又有一个问题了,我已经删了的还是被计算在内了,怎么办?
我减去它与已经删了的构成的逆序对的个数不就好了吗?
于是问题变成了:
每一次在已经删除的元素里面找 [l,r] 里面小于某个数的元素的个数。
这个问题显然丢给主席树。
注:记得开大空间!我就是数组开小了然后 MLE* 2 。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 100010
using namespace std;
int n,m;
long long ans=0;
int val[MAXN],pos[MAXN],sum_one[MAXN],sum_two[MAXN];
inline int read(){
int date=0,w=1;char c=0,last=0;
while(c<'0'||c>'9'){last=c;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
if(last=='-')w=-1;
return date*w;
}
namespace CT{
int size=1,s1,s2,root[MAXN],lrt[MAXN/1000+10],rrt[MAXN/1000+10];
struct Charman_Tree{
int l,r,sum;
}a[MAXN*100];
void insert(int k,int l,int r,int &rt){
a[size]=a[rt];rt=size++;
a[rt].sum++;
if(l==r)return;
int mid=l+r>>1;
if(k<=mid)insert(k,l,mid,a[rt].l);
else insert(k,mid+1,r,a[rt].r);
}
int query_front(int l,int r,int k){
if(l==r)return 0;
int mid=l+r>>1,t=0;
for(int i=1;i<=s1;i++)t-=a[a[lrt[i]].r].sum;
for(int i=1;i<=s2;i++)t+=a[a[rrt[i]].r].sum;
if(k<=mid){
for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].l;
for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].l;
return t+query_front(l,mid,k);
}
else{
for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].r;
for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].r;
return query_front(mid+1,r,k);
}
}
int query_next(int l,int r,int k){
if(l==r)return 0;
int mid=l+r>>1,t=0;
for(int i=1;i<=s1;i++)t-=a[a[lrt[i]].l].sum;
for(int i=1;i<=s2;i++)t+=a[a[rrt[i]].l].sum;
if(k>mid){
for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].r;
for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].r;
return t+query_next(mid+1,r,k);
}
else{
for(int i=1;i<=s1;i++)lrt[i]=a[lrt[i]].l;
for(int i=1;i<=s2;i++)rrt[i]=a[rrt[i]].l;
return query_next(l,mid,k);
}
}
inline int lowbit(int x){return x&(-x);}
inline void update(int x,int v){
for(int i=x;i<=n;i+=lowbit(i))insert(v,1,n,root[i]);
}
inline int get_answer(int l,int r,int k){
int s=0;
s1=s2=0;
for(int i=0;i;i-=lowbit(i))lrt[++s1]=root[i];
for(int i=l;i;i-=lowbit(i))rrt[++s2]=root[i];
s+=query_front(1,n,k);
s1=s2=0;
for(int i=r-1;i;i-=lowbit(i))lrt[++s1]=root[i];
for(int i=n;i;i-=lowbit(i))rrt[++s2]=root[i];
s+=query_next(1,n,k);
return s;
}
}
namespace BIT{
int tree[MAXN];
inline void init(){memset(tree,0,sizeof(tree));}
inline int lowbit(int x){return x&(-x);}
inline void update(int x,int v){for(;x<=n;x+=lowbit(x))tree[x]+=v;}
inline int sum(int x){int s=0;for(;x;x-=lowbit(x))s+=tree[x];return s;}
}
void work(){
int x,id;
while(m--){
printf("%lld
",ans);
x=read();x=pos[x];
ans-=(sum_one[x]+sum_two[x]-CT::get_answer(x-1,x+1,val[x]));
CT::update(x,val[x]);
}
}
void init(){
n=read();m=read();
for(int i=1;i<=n;i++){
val[i]=read();
pos[val[i]]=i;
sum_one[i]=BIT::sum(n)-BIT::sum(val[i]);
ans+=(long long)sum_one[i];
BIT::update(val[i],1);
}
BIT::init();
for(int i=n;i>=1;i--){
sum_two[i]=BIT::sum(val[i]-1);
BIT::update(val[i],1);
}
}
int main(){
init();
work();
return 0;
}