您的位置:首页 > 其它

[CQOI2011]动态逆序对

2018-01-09 10:15 302 查看

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

Sample Output

5

2

2

1

样例解释

(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

HINT

N<=100000 M<=50000

[b]树状数组+主席树[/b]

[b]每一次删除x,我们求出前面大于x和后面小于x的个数减去[/b]

[b]这个用按位置作为前缀加入元素的主席树[/b]

[b]但有一个问题就是,作为前缀的一个元素x被删,后面的x+1~n就都要修改更新[/b]

[b]这样就会退化成O(n^2logn)[/b]

[b]所以用树状数组维护主席树[/b]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long lol;
int pos,root[100001],ch[90*100001][2],n,m,a[100001],p[100001];
lol ans;
int sum[90*100001];
void update(int &rt,int l,int r,int x,int d)
{
if (!rt)
rt=++pos;
sum[rt]+=d;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) update(ch[rt][0],l,mid,x,d);
else update(ch[rt][1],mid+1,r,x,d);
}
lol query1(int rt,int l,int r,int x)
{
if (l==r) return sum[rt];
int mid=(l+r)>>1;
if (x<=mid) return query1(ch[rt][0],l,mid,x)+sum[ch[rt][1]];
else return query1(ch[rt][1],mid+1,r,x);
}
lol query2(int rt,int l,int r,int x)
{
if (l==r)
return sum[rt];
int mid=(l+r)>>1;
if (x<=mid) return query2(ch[rt][0],l,mid,x);
else return query2(ch[rt][1],mid+1,r,x)+sum[ch[rt][0]];
}
int main()
{int i,j,x,k;
cin>>n>>m;
for (i=1;i<=n;++i)
{
scanf("%d",&a[i]);
p[a[i]]=i;
for (j=i;j<=n;j+=lowbit(j))
update(root[j],1,n,a[i],1);
}
for (i=1;i<=n;++i)
{
for (j=i-1;j;j-=lowbit(j))
ans+=query1(root[j],1,n,a[i]);
}
for (i=1;i<=m;++i)
{
scanf("%d",&x);
printf("%lld\n",ans);
k=p[x];
for (j=k-1;j;j-=lowbit(j))
ans-=query1(root[j],1,n,x);
for (j=k;j;j-=lowbit(j))
ans+=query2(root[j],1,n,x);
for (j=n;j;j-=lowbit(j))
ans-=query2(root[j],1,n,x);
for (j=k;j<=n;j+=lowbit(j))
update(root[j],1,n,x,-1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: