树状数组 || 线段树 || Luogu P5200 [USACO19JAN]Sleepy Cow Sorting

时间:2021-11-17 19:33:42

题面:P5200 [USACO19JAN]Sleepy Cow Sorting

题解:

最小操作次数(记为k)即为将序列倒着找第一个P[i]>P[i+1]的下标,然后将序列分成三部分:前缀部分(待转移部分),k,后缀部分(不需转移部分)。

用树状数组维护前缀部分每一个数挪到后缀部分所需的最小代价(即插到第一个小于它的数前)(这部分完全可以用线段树做)。

代码:

 #include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int maxn=(1e5)+;
ll P[maxn],N,k,t[maxn];
inline void Add(ll x){
for(;x<=N;x+=x&(-x))t[x]++;
return;
}
inline ll Sum(ll x){
ll sum=;
for(;x>;x-=x&(-x))sum+=t[x];
return sum;
}
int main(){
scanf("%lld",&N);
for(int i=;i<=N;i++)scanf("%lld",&P[i]);
k=;//若查询不到,k也应为0,所以先置为0
for(int i=N-;i>=;i--)
if(P[i]>P[i+]){k=i; break;}
printf("%lld\n",k);
if(k==)return ;
for(int i=k+;i<=N;i++)Add(P[i]);
for(int i=;i<=k;i++){
printf("%lld ",k-i+Sum(P[i]));
Add(P[i]);
}
return ;
}

By:AlenaNuna