[Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 6058 Solved: 2117
[Submit][Status][Discuss]
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>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
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
Source
题解:
普通的树状数组,无法记录位置,不能知道一次之后记录的是所以位置的信息,
一次删除的时候,不能知道哪些值是比它小的,因为位置的影响,
所以需要树套树,在开一层位置,这样就可以了,动态开点,n logn log n的空间复杂度。
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath> #define N 100007
#define M 10000007
using namespace std;
int n,m,cnt;
int a[N],id[N],bit[N],lson[M],rson[M],tree[M];
long long ans; int lowbit(int x){return x&-x;}
void addy(int &u,int l,int r,int x,int y)
{
if(!u)u=++cnt;
if(l==r){tree[u]+=y;return;}
int mid=(l+r)>>;
if(x<=mid) addy(lson[u],l,mid,x,y);
else addy(rson[u],mid+,r,x,y);
tree[u]=tree[lson[u]]+tree[rson[u]];
}
void addx(int x,int y,int val)
{
for (int i=x;i<=n;i+=lowbit(i))
addy(i,,n,y,val);
}
int queryy(int u,int l,int r,int i,int j)
{
if(!u) return ;
if(l==i&&r==j) return tree[u];
int mid=(l+r)>>;
if(j<=mid) return queryy(lson[u],l,mid,i,j);
else if(i>mid) return queryy(rson[u],mid+,r,i,j);
return queryy(lson[u],l,mid,i,mid)+queryy(rson[u],mid+,r,mid+,j);
}
int queryx(int x,int l,int r)
{
int ans=;
for (int i=x;i>=;i-=lowbit(i))
ans+=queryy(i,,n,l,r);
return ans;
}
int main()
{
scanf("%d%d",&n,&m),cnt=n;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
ans+=(long long)queryx(i-,a[i]+,n);
id[a[i]]=i;
addx(i,a[i],);
}
while(m--)
{
printf("%lld\n",ans);
int x;scanf("%d",&x);
ans-=(long long)queryx(id[x]-,x+,n);
ans-=(long long)queryx(n,,x-);
ans+=(long long)queryx(id[x]-,,x-);
addx(id[x],x,-);
}
}