怀念一下归并+逆序对

/*
codevs 4163 神犇与逆序对 
*/
#include<cstdio>
#define ll long long
#define maxn 1000010
using namespace std;
ll n,a[maxn],b[maxn],ans;
ll init()
{
    ll x=0;char s;s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x;
}
void Merge_sort(ll l,ll r)
{
    if(l==r)return ;
    ll mid=(l+r)/2;
    Merge_sort(l,mid);
    Merge_sort(mid+1,r);
    ll i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
      {
          if(a[i]>a[j])
            {
                b[k++]=a[j++];ans+=mid-i+1;
          }
        else b[k++]=a[i++];
      }
    while(i<=mid)b[k++]=a[i++];
    while(j<=r)b[k++]=a[j++];
    for(ll i=l;i<=r;i++)a[i]=b[i];
}
int main()
{
    n=init();
    for(ll i=1;i<=n;i++)
      a[i]=init();
    Merge_sort(1,n);
    printf("%lld
",ans);
    return 0;
}/*

/*
codevs 3286 火柴排队 
首先要知道两点 1:两列火柴高度排名大小相同时排列答案最优 2:移动两个序

列和移动一个序列步数一样
证明嘛 自己想吧 ^ ^ 假设我们只移动第二个序列 消耗步数就是求下逆序对
现在的问题就是求出第二个序列需要怎么移动
求逆序对我们想到用归并排序 那么移动的目标就是有序序列1-n
怎么和“两列火柴高度排名大小相同”联系起来呢
这样 我们维护a1 a2 p1 p2几个序列
a1[i]=j:原序列1中i位置处的高度排名 a2同理
p1[i]=j:原序列1中高度排名i的位置 
那p1[a2[i]]就是原序列2中i位置处的高度排名那么大的在1中的位置
我们把这个位置记在p2[i]中 那就是需要把i移动到p2[i] 也就是逆序对的个数
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 99999997
#define maxn 2000020
using namespace std;
int n,a1[maxn],a2[maxn],p[maxn],l[maxn],w[maxn];
long long ans;
struct node
{
    int o,h;
}s1[maxn],s2[maxn];
int init()
{
    int x=0;char s;s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x;
}
int cmp(const node &x,const node &y)
{
    return x.h<y.h;
}
void Merge(int l,int r)
{
    if(l==r)return ;
    int mid=(l+r)/2;
    Merge(l,mid);
    Merge(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
      {
          if(p[i]>p[j])
            {
                w[k++]=p[j++];ans=(ans+mid-i+1)%mod;
          }
        else w[k++]=p[i++];
      }
    while(i<=mid)w[k++]=p[i++];
    while(j<=r)w[k++]=p[j++];
    for(int i=l;i<=r;i++)p[i]=w[i];
}
int main()
{
    n=init();
    for(int i=1;i<=n;i++)
      {
          s1[i].h=init();
          s1[i].o=i;
      }
    for(int i=1;i<=n;i++)
      {
          s2[i].h=init();
          s2[i].o=i;
      }
    sort(s1+1,s1+1+n,cmp);
    sort(s2+1,s2+1+n,cmp);
    for(int i=1;i<=n;i++)
      {
          a1[s1[i].o]=i;
          a2[s2[i].o]=i;
      }
    for(int i=1;i<=n;i++)
      l[a1[i]]=i;
    for(int i=1;i<=n;i++)
      p[i]=l[a2[i]];
    Merge(1,n);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/yanlifneg/p/5533845.html