C85 树状数组+逆序对 P1966 [NOIP2013 提高组] 火柴排队

视频链接:271 树状数组+逆序对 P1966 [NOIP2013 提高组] 火柴排队_哔哩哔哩_bilibili

  

 

 

Luogu P1966 [NOIP2013 提高组] 火柴排队

// 逆序对+树状数组 O(nlogn)
#include<cstdio>
#include<algorithm>
using namespace std;

#define lowb(x) (x&-x)
const int N=100010, mod=99999997;
struct node{
  int val,pos; //值,位置
  bool operator<(node b){
    return val<b.val;
  }
}a[N],b[N];
int n,ans,s[N],c[N]; //c:位置映射

void change(int x,int k){ //向后修
  while(x<=n) s[x]=(s[x]+k)%mod,x+=lowb(x);
}
int query(int x){ //向前查
  int t=0;
  while(x) t=(t+s[x])%mod,x-=lowb(x);
  return t;
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    scanf("%d",&a[i].val),a[i].pos=i;
  for(int i=1;i<=n;i++)
    scanf("%d",&b[i].val),b[i].pos=i;
  sort(a+1,a+n+1); sort(b+1,b+n+1);
  for(int i=1;i<=n;i++) c[a[i].pos]=b[i].pos;
  for(int i=n;i;i--){ //从后面找<ci的个数
    ans=(ans+query(c[i]-1))%mod;
    change(c[i],1);
  }
  printf("%d",ans);
}

 

// 逆序对+归并排序 O(nlogn)
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=100010, mod=99999997;
struct node{
  int val,pos; //值,位置
  bool operator<(node b){
    return val<b.val;
  }
}a[N],b[N];
int n,ans,c[N],d[N]; //c:位置映射

void merge(int l,int r){
  if(l>=r) return;
  int mid=l+r>>1;
  merge(l,mid);
  merge(mid+1,r); //拆分
  
  int i=l,j=mid+1,k=l; //合并
  while(i<=mid && j<=r){
    if(c[i]<=c[j]) d[k++]=c[i++];
    else d[k++]=c[j++], ans=(ans+mid-i+1)%mod;
  }
  while(i<=mid) d[k++]=c[i++];
  while(j<=r) d[k++]=c[j++];
  for(i=l; i<=r; i++) c[i]=d[i];
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    scanf("%d",&a[i].val),a[i].pos=i;
  for(int i=1;i<=n;i++)
    scanf("%d",&b[i].val),b[i].pos=i;
  sort(a+1,a+n+1); sort(b+1,b+n+1);
  for(int i=1;i<=n;i++) c[a[i].pos]=b[i].pos;
  merge(1,n);
  printf("%d",ans);
}

 

posted @ 2023-12-31 21:45  董晓  阅读(183)  评论(0编辑  收藏  举报