【康复训练】【cdq分治】【BZOJ】3295: [Cqoi2011]动态逆序对

Description

对于序列A,它的逆序对数定义为满足i

题解

cdq分治.
将删除操作倒序看就是加入操作,然后就是一个经典的三位偏序问题了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100006
#define maxm 50006
#define lowbit(x) (x&-x)
#define LL long long
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int n,m,nn,tem,t[maxn],a[maxn],b[maxn],p[maxn],f[maxn];
LL ans[maxm];
struct data{
    int t,x,y;
    bool operator <(const data&b)const{return x<b.x;}
}c[maxn],tmp[maxn];
bool vis[maxn];
void add(int x,int y){for(;x<=n;x+=lowbit(x))f[x]+=y;}
int get(int x){
    int sum=0;
    for(;x;x-=lowbit(x))sum+=f[x];
    return sum;
}
void sort(int l,int r){
    int mid=l+r>>1;
    int i=l,j=mid+1;
    for(int k=l;k<=r;k++)tmp[k]=c[k];
    for(int k=l;k<=r;k++)
        if(i<=mid&&(tmp[i]<tmp[j]||j>r))c[k]=tmp[i++];else c[k]=tmp[j++];
}
void work(int l,int r){
    if(l>=r)return;
    int mid=l+r>>1;
    work(l,mid);work(mid+1,r);
    int j=l;tem=0;
    for(int i=mid+1;i<=r;i++){
        while(j<=mid&&c[j].x<c[i].x)add(n-c[j].y+1,1),t[++tem]=n-c[j].y+1,j++;
        ans[c[i].t]+=get(n-c[i].y+1);
    }
    for(int i=1;i<=tem;i++)add(t[i],-1);
    j=mid;tem=0;
    for(int i=r;i>mid;i--){
        while(j>=l&&c[j].x>c[i].x)add(c[j].y,1),t[++tem]=c[j].y,j--;
        ans[c[i].t]+=get(c[i].y);
    }
    for(int i=1;i<=tem;i++)add(t[i],-1);
    sort(l,r);
}
int main(){
    freopen("reverse.in","r",stdin);
    freopen("reverse.out","w",stdout);
    n=_read();m=_read();
    memset(vis,1,sizeof(vis));
    for(int i=1;i<=n;i++)a[i]=_read(),p[a[i]]=i;
    for(int i=1;i<=m;i++)b[i]=_read(),vis[b[i]]=0;
    for(int i=1;i<=n;i++)if(vis[a[i]])c[++nn].x=i,c[nn].y=a[i],c[nn].t=0;
    for(int i=m;i>=1;i--)c[++nn].x=p[b[i]],c[nn].y=b[i],c[nn].t=m-i+1;
    work(1,n);
    for(int i=1;i<=m;i++)ans[i]+=ans[i-1];
    for(int i=m;i>=1;i--)printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/FYOIER/article/details/80512901
今日推荐