1715. [CQOI2011]动态逆序对
输入文件:inverse.in 输出文件:inverse.out 简单对比
时间限制:2 s 内存限制:128 MiB
【题目描述】
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
【输入格式】
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
【输出格式】
输出包含m行,依次为删除每个元素之前,逆序对的个数。
【样例输入】
5 4
1
5
3
4
2
5
1
4
2
【样例输出】
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
【提示】
N<=100000 M<=50000
时间、位置、大小三维偏序
每个数加入后,可能有两种方式构成逆序对,比自己位置靠前但数值小的,比自己位置靠后但数值大的。所以要写两次CDQ。求出的每个数加入后新产生的逆序对的数量。所以还要写一个前缀和。
就这么个东西,写了一天多!水平太差!
/*
COGS1715:动态逆序对
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+10;
const int maxm=5e4+10;
int n,m;
struct node
{
int pos,x,t;
bool operator < (const node &a)const
{
// if(t!=a.t)return t<a.t;
if(pos!=a.pos)return pos<a.pos;
return 0;
}
}sz[maxn],f[maxn];
int ans[maxm],ansf[maxm];
int tt[maxn];
bool cmp(node a,node b)
{
if(a.t!=b.t)return a.t<b.t;
if(a.pos!=b.pos)return a.pos<b.pos;
}
bool cmpf(node a,node b)
{
if(a.t!=b.t)return a.t<b.t;
if(a.pos!=b.pos)return a.pos>b.pos;
}
int sm[maxn];
void add(int sm[],int pos,int x)
{
for(int i=pos;i<=n;i+=i&-i)sm[i]+=x;
}
int query(int sm[],int pos)
{
int ret=0;
for(int i=pos;i;i-=i&-i)ret+=sm[i];
return ret;
}
void cdq(int l,int r)
{
if(l==r)return ;
int mid=(l+r)>>1;
cdq(l,mid);
cdq(mid+1,r);
int q=l,h=mid+1,p=l;
while(q<=mid&&h<=r)
{
if(sz[q].pos<sz[h].pos)//sz[q]时间小,位置前
{
f[p]=sz[q];
add(sm,sz[q].x,1);
//add(smm,sz[q].x,1);
//ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
++p;++q;
}
else//sz[q]时间小,位置后
{
f[p]=sz[h];
ans[sz[h].t]+=q-l-query(sm,sz[h].x);
++p;++h;
}
}
while(q<=mid)
{
f[p]=sz[q];
add(sm,sz[q].x,1);
//add(smm,sz[q].x,1);
//ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
++p;++q;
}
while(h<=r)
{
f[p]=sz[h];
ans[sz[h].t]+=q-l-query(sm,sz[h].x);
++p;++h;
}
for(int i=l;i<=mid;++i)add(sm,sz[i].x,-1);
// for(int i=mid+1;i<=r;++i)add(smm,sz[i].x,-1);
for(int i=l;i<=r;++i)sz[i]=f[i];
}
void cdqf(int l,int r)
{
if(l==r)return ;
int mid=(l+r)>>1;
cdqf(l,mid);
cdqf(mid+1,r);
int q=l,h=mid+1,p=l;
while(q<=mid&&h<=r)
{
if(sz[q].pos>sz[h].pos)//sz[q]时间小,位置前
{
f[p]=sz[q];
add(sm,sz[q].x,1);
//add(smm,sz[q].x,1);
//ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
++p;++q;
}
else//sz[q]时间小,位置后
{
f[p]=sz[h];
ansf[sz[h].t]+=query(sm,sz[h].x);
++p;++h;
}
}
while(q<=mid)
{
f[p]=sz[q];
add(sm,sz[q].x,1);
//add(smm,sz[q].x,1);
//ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
++p;++q;
}
while(h<=r)
{
f[p]=sz[h];
ansf[sz[h].t]+=query(sm,sz[h].x);
++p;++h;
}
for(int i=l;i<=mid;++i)add(sm,sz[i].x,-1);
// for(int i=mid+1;i<=r;++i)add(smm,sz[i].x,-1);
for(int i=l;i<=r;++i)sz[i]=f[i];
}
signed main()
{
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%lld",&sz[i].x);
sz[i].pos=i;
}
for(int x,i=1;i<=m;++i)
{
scanf("%lld",&x);
tt[x]=m-i+1;
}
for(int i=1;i<=n;++i)sz[i].t=tt[sz[i].x];
sort(sz+1,sz+1+n,cmp);
cdq(1,n);
sort(sz+1,sz+1+n,cmpf);
cdqf(1,n);
ans[0]=0;
for(int i=0;i<=m;++i)ans[i]+=ansf[i];
for(int i=1;i<=m;++i)ans[i]+=ans[i-1];
// printf("%d\n",ans[0]+ansf[0]);
for(int i=m;i>=1;--i)printf("%lld\n",ans[i]);
return 0;
}
/*s
3 2
3 1 2
3 1
2
2
*/