车厢重组
题目描述
在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转 180 180 180 度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。他退休后,火车站决定将这一工作自动化,其中一项重要的工作是编一个程序,输入初始的车厢顺序,计算最少用多少步就能将车厢排序。
输入格式
共两行。
第一行是车厢总数 N ( ≤ 10000 ) N( \le 10000) N(≤10000)。
第二行是 N N N 个不同的数表示初始的车厢顺序。
(注:实际上数据中并不都在同一行,有可能分行输入)
输出格式
一个整数,最少的旋转次数。
样例 #1
样例输入 #1
4
4 3 2 1
样例输出 #1
6
https://www.luogu.com.cn/article/vrsmha0q
与常规的树状数组(直接将数字放入,看看已经放入的数中有几个比自己大)不同,这里每个叶子节点记录的是第i个是否入场。先排序后记录入场实际上在第i大的数入场时,比它大的数都已经入场了,这时候只需要记录在他之前入场的个数即可。
妙哉,这样就不需要进行离散化了
cpp
#include <bits/stdc++.h>
using namespace std;
int n,ans=0;
int a[10005],b[10005],c[10005];
int lowbit(int x){return x&-x;}
void add(int x,int v)
{
while(x<=n){
a[x]+=v;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while(x>=1){
ans+=a[x];
x-=lowbit(x);
}
return ans;
}
bool cmp(const int &a,const int &b)
{
return a>b;
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
cin>>b[i],c[b[i]]=i;
///稳定排序是为了防止有相同元素的情况,这可能导致答案出错
stable_sort(b+1,b+1+n,cmp);
///可在此处改变插入顺序
for(int i=1;i<=n;++i){
add(c[b[i]],1);
ans+=sum(c[b[i]]-1);
}
cout<<ans;
return 0;
}