逆序对(inversion)

逆序对(inversion)

题目描述

对于序列AA,它的逆序对数定义为满足i<ji<j,且Ai>AjAi>Aj 的数对i,ji,j的个数。

现给你11到nn的一个排列,并按照某种顺序依次删除mm个元素。现请你求出在每次删除一个元素之前整个序列的逆序对总个数。

输入

第一行包含两个整数nn和mm。

第二行包含nn个数,代表初始序列。

接下来的mm行,每一个整数表示第ii行,每一个整数表示第ii次删除的数(保证在此之前未曾删除过)。

输出

共mm行,表示第ii次删数前整个序列的逆对总个数。

扫描二维码关注公众号,回复: 3365791 查看本文章

样例输入

5 4
1 5 3 4 2
5
1
4
2

样例输出

5
2
2
1

提示


动态逆序对

假设删除时间为ti,值为xi,下标idi

如果i要对j进行贡献

必须满足ti>tj,idi<idj,xi>xj

ti>tj,idi>idj,xi<xj

三维偏序就CDQ啦

看错题调一天

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 1000005
#define ll long long
using namespace std;
int n,m,c;
ll sum[maxn],tree[maxn],ans[maxn];
int p[maxn];
struct node{
    int id,x,t;
}s[maxn],a[maxn];
bool cmp(node a,node b){
    return a.t>b.t;
}
bool X(node a,node b){
    return a.x>b.x;
}
bool ID(node a,node b){
    return a.id>b.id;
}
void jia(int k,int val){
    for(int i=k;i<=n;i+=i&-i)tree[i]+=val;
}
ll ask(int k){
    ll su=0;
    for(int i=k;i;i-=i&-i)su+=tree[i];
    return su;
}
void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    sort(s+l,s+mid+1,X);sort(s+mid+1,s+r+1,X);
    //cout<<l<<' '<<r<<endl;
    int i=l;
    for(int j=mid+1;j<=r;j++){
        while(s[i].x>s[j].x&&i<=mid){
            jia(s[i].id,1);i++;
            //cout<<s[i].id<<' ';
        }
        ans[s[j].t]+=ask(s[j].id);
    }
    for(int j=l;j<i;j++)jia(s[j].id,-1);
    //merge(s+l,s+mid+1,s+mid+1,s+r+1,a,X);
    //for(int i=0;i<=l+r-1;i++)s[i+l]=a[i];
}
 
void cd(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    cd(l,mid);cd(mid+1,r);
    sort(s+l,s+mid+1,ID);sort(s+mid+1,s+r+1,ID);
    int i=l;
    for(int j=mid+1;j<=r;j++){
        while(s[i].id>s[j].id&&i<=mid){
            jia(s[i].x,1);i++;
        }
        ans[s[j].t]+=ask(s[j].x);
    }
    for(int j=l;j<i;j++)jia(s[j].x,-1);
    //merge(s+l,s+mid+1,s+mid+1,s+r+1,a,ID);
    //for(int i=0;i<=l+r-1;i++)s[i+l]=a[i];
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%d",&s[i].x);p[s[i].x]=i;
        s[i].id=i;
    }
    for(int i=1;i<=m;i++){
        scanf("%d",&c);
        s[p[c]].t=i;
    }
    int top=m;
    for(int i=1;i<=n;i++)if(!s[i].t)s[i].t=++top;
    sort(s+1,s+n+1,cmp);
    cdq(1,n);
    sort(s+1,s+n+1,cmp);
    cd(1,n);
    for(int i=n;i>=1;i--)sum[i]=sum[i+1]+ans[i];
//    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";cout<<endl;
    for(int i=1;i<=m;i++){
        printf("%lld\n",sum[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/liankewei123456/article/details/82226921