火柴排队

首先我们对两个数组排序,对齐每位,然后记录一个火柴对应的另一个火柴,这时我们得到了一个序列:第i根火柴需要被放到第j个位置,然后原来火柴是按升序排序的,这时需要计算逆序对,也就是交换的最少次数

树状数组 x[i],y[i]:编号,然后z[x[i]]=y[i]:第一列第x[i]根火柴应该对应第二列第y[i]根火柴,也就是说x[i]应该被放到y[i],因为第二列要对应的火柴在y[i]

因为最先开始火柴是按升序排列,所以求逆序对就可以了

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll inf=99999997;
int n;
ll a[100010],b[100010],x[100010],y[100010],tree[600010],z[100010];
inline bool cp1(int x,int y){return a[x]<a[y];}
inline bool cp2(int x,int y){return b[x]<b[y];}
inline void add(int x)
{
    for(int t=x;t<=n;t+=(t&(-t))) tree[t]++;
}
inline ll sum(int x)
{
    ll ret=0; 
    for(int t=x;t;t-=(t&(-t))) ret+=tree[t];
    return ret;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",a+i);
        x[i]=y[i]=i;
    }
    for(int i=1;i<=n;i++) scanf("%d",b+i);
    sort(x+1,x+n+1,cp1);
    sort(y+1,y+n+1,cp2);
    for(int i=1;i<=n;i++) 
    {
        z[x[i]]=y[i];
    }
    ll ans=0;
    for(int i=1;i<=n;i++) 
    {
        ans+=i-sum(z[i])-1;add(z[i]);
        ans%=inf;
    }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/19992147orz/p/6028739.html