BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

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

Sample Output

5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。


 

设每个值v删除的时间为t,位置为p。

对于那些没有删除的值,可以当成删除时间为n+1。

于是我们要统计删除一个数后逆序对数量变少了多少。

即统计删除时间大于tx,位置小于px,值大于vx的y的个数。

删除时间大于tx,位置大于px,值小于vx的y的个数。

按删除时间从大到小排序,然后CDQ分治内部按位置排序,分别统计这两部分。

 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100050
typedef long long ll;
int b[N],pos[N],n,m,c[N],is[N];
ll ans[N],lstans;
struct A {
    int t,p,v;
}a[N],t[N];
bool cmp(const A &x,const A &y) {
    return x.t>y.t;
}
void fix(int x,int v) {for(;x<=n;x+=x&(-x)) c[x]+=v;}
ll inq(int x) {ll re=0;for(;x;x-=x&(-x)) re+=c[x]; return re;}
void solve(int l,int r) {
    if(l==r) return ;
    int mid=(l+r)>>1;
    solve(l,mid); solve(mid+1,r);
    int i=l,j=l,k=mid+1;
    while(j<=mid&&k<=r) {
        if(a[j].p<a[k].p) fix(a[j].v,1),t[i++]=a[j++];
        else ans[a[k].t]+=inq(n)-inq(a[k].v),t[i++]=a[k++];
    }
    while(j<=mid) fix(a[j].v,1),t[i++]=a[j++];
    while(k<=r) ans[a[k].t]+=inq(n)-inq(a[k].v),t[i++]=a[k++];
    for(i=l;i<=mid;i++) fix(a[i].v,-1);
     
    j=mid,k=r;
    while(j>=l&&k>=mid+1) {
        if(a[j].p>a[k].p) fix(a[j].v,1),j--;
        else ans[a[k].t]+=inq(a[k].v-1),k--;
    }
    while(j>=l) fix(a[j].v,1),j--;
    while(k>=mid+1) ans[a[k].t]+=inq(a[k].v-1),k--;
    for(i=l;i<=mid;i++) fix(a[i].v,-1);
    for(i=l;i<=r;i++) a[i]=t[i];
}
int main() {
    scanf("%d%d",&n,&m);
    int i,j;
    for(i=1;i<=n;i++) scanf("%d",&b[i]),lstans+=i-1-inq(b[i]),pos[b[i]]=i,fix(b[i],1);
    memset(c,0,sizeof(c));
    for(i=1;i<=m;i++) {
        scanf("%d",&a[i].v); a[i].p=pos[a[i].v]; a[i].t=i; is[a[i].v]=1;
    }
    for(j=m,i=1;i<=n;i++) {
        if(!is[i]) a[++j]=(A){n+1,pos[i],i};
    }
    sort(a+1,a+n+1,cmp);
    solve(1,n);
    //for(i=1;i<=m;i++) printf("%lld\n",ans[i]);
    for(i=1;i<=m;i++) printf("%lld\n",lstans),lstans-=ans[i];
}

 

posted @ 2018-06-24 08:26  fcwww  阅读(143)  评论(0编辑  收藏  举报