题目描述
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
输入输出格式
输入格式:
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
输出格式:
输出包含m行,依次为删除每个元素之前,逆序对的个数。
输入输出样例
输入样例#1:
5 4
1
5
3
4
2
5
1
4
2
输出样例#1:
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
说明
N<=100000 M<=50000
分析:
本来打的树套树,没打完就感冒了= =。仔细一想还不如打分块。我们每删掉一个数,相当于减去前面比他大的个数+后面比他小的个数。于是,我们可以把每个块先排个序,二分这个块。对于自己所在块,暴力该块减小的逆序对,并删掉这个数(暴力把比他大的前移)。不懂为什么%lld会错,最后打了cout。至于一开始的逆序对数可以用树状数组暴力(真的超级暴力)。
代码:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
const int maxn=1e5+7;
using namespace std;
int id[maxn],a[maxn],b[maxn],l[maxn],r[maxn],belong[maxn];
int n,m,block,sum,i,x,j;
long long ans=0;
long long t[maxn*5];
int lowbit(int x)
{
return x&(-x);
}
void updata(int x,int k)
{
while (x<=n)
{
t[x]+=(long long)k;
x+=lowbit(x);
}
}
long long getsum(int x)
{
long long ans=0;
while (x>0)
{
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
void kp(int l,int r)
{
if (l>r) return;
int i=l; int j=r;
int temp;
int key=b[(l+r)/2];
while (i<=j)
{
while (b[i]<key) i++;
while (b[j]>key) j--;
if (i<=j)
{
temp=b[i]; b[i]=b[j]; b[j]=temp;
i++; j--;
}
}
kp(l,j);
kp(i,r);
}
void build_block()
{
block=trunc(sqrt(n*2));
sum=n/block+(n%block!=0);
for (int i=1;i<=sum;i++)
{
l[i]=(i-1)*block+1;
r[i]=i*block;
}
r[sum]=n;
for (int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
for (int i=1;i<=sum;i++) kp(l[i],r[i]);
}
int find(int u,int l,int r)
{
int ans=l-1,mid;
while (l<=r)
{
mid=(l+r)/2;
if (b[mid]<u) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int main()
{
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
id[a[i]]=i;
b[i]=a[i];
}
build_block();
for (i=1;i<=n;i++)
{
ans+=(i-1)-getsum(a[i]-1);
updata(a[i],1);
}
cout<<ans;
printf("\n");
for (j=1;j<m;j++)
{
scanf("%d",&x);
int u=id[x];
int s=l[belong[u]+1]-1;
if (s==-1) s=n;
for (i=l[belong[u]];i<=s;i++)
{
if (a[i]==-1) continue;
if ((a[i]>a[u]) && (i<u)) ans--;
if ((a[i]<a[u]) && (i>u)) ans--;
}
a[u]=-1;
for (i=1;i<belong[u];i++)
{
ans-=r[i]-find(x,l[i],r[i]);
}
for (i=belong[u]+1;i<=sum;i++)
{
ans-=find(x,l[i],r[i])-l[i]+1;
}
int c=find(x,l[belong[u]],r[belong[u]]);
for (i=c+1;i<r[belong[u]];i++) b[i]=b[i+1];
r[belong[u]]--;
cout<<ans;
printf("\n");
}
return 0;
}