BZOJ4240 有趣的家庭菜园

题面在这里

最终状态一定是一个先增后减的峰形

然后交换次数其实等于 最终状态的\(id\)序列的逆序对数

考虑按高度从小到大加入最终的序列,只能放在两端,分别统计答案,选小的那个

用树状数组维护 未加入的点的\(id\)分布情况

示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn=300005;
int n;
struct data{
int x,id;
bool operator<(const data&b)const {return x<b.x;}
}a[maxn];
int b1[maxn],b2[maxn];
#define lowbit(x) ((x)&-(x))
void ist(int x,int w){
for (int i=x;i<=n;i+=lowbit(i)) b1[i]+=w;
for (int i=x;i>=1;i-=lowbit(i)) b2[i]+=w;
}
int qry(int x){
int r1=0,r2=0;
for (int i=x;i>=1;i-=lowbit(i)) r1+=b1[i];
for (int i=x;i<=n;i+=lowbit(i)) r2+=b2[i];
return min(r1,r2);
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].id=i,ist(i,1);
sort(a+1,a+1+n);
ll ans=0;
for (int i=1,j=1;i<=n;i=j){
for (j=i;j<=n&&a[i].x==a[j].x;j++) ist(a[j].id,-1);
for (j=i;j<=n&&a[i].x==a[j].x;j++) ans+=qry(a[j].id);
}
printf("%lld",ans);
return 0;
}