题解:[HNOI2002] 营业额统计
题意分析
给定 \(a_1,a_2,a_3,\cdots,a_n\),对于每一个 \(a_i\)(\(1<i\leq n\)),在 \(a_1,a_2,\cdots,a_{i-1}\) 中找一个 \(a_j\),使得 \(\sum\vert a_i-a_j\vert\) 最小。
即找 \(a_i\) 的前驱与后继。
很容易想到平衡树维护。
$\text{Updated at 2025/7/20}$
此时迁移 Blog 的我非常懵 b,我理解不了一个普及−(虽然当时是普及/提高−)的题目我为什么要写 FHQ Treap。
况且 $n\leq32767$,你直接 $\mathcal O\left(n^2\log n\right)$ 排序写完不就好了吗?
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<random>
using namespace std;
#define int long long
const int N=1e5;
mt19937 Rand(time(0));
int root;
struct treap{
struct node{
int value,rand,size;
int left,right;
}t[N+1];
void up(int p){
t[p].size=t[t[p].left].size+t[t[p].right].size+1;
}
void split(int p,int x,int &l,int &r){
if(p==0)l=r=0;
else{
if(t[p].value<=x){
l=p;
split(t[p].right,x,t[p].right,r);
}else{
r=p;
split(t[p].left,x,l,t[p].left);
}up(p);
}
}
int merge(int l,int r){
if(!l||!r)return l|r;
if(t[l].rand<t[r].rand){
t[l].right=merge(t[l].right,r);
up(l);
return l;
}else{
t[r].left=merge(l,t[r].left);
up(r);
return r;
}
}
int create(int x){
static int top;
t[++top]={x,Rand(),1,0,0};
return top;
}
void insert(int x){
int l,r;
split(root,x,l,r);
root=merge(merge(l,create(x)),r);
}
void remove(int x){
int l,r,pl;
split(root,x,l,r);
split(l,x-1,l,pl);
pl=merge(t[pl].left,t[pl].right);
root=merge(merge(l,pl),r);
}
int rank(int x){
int l,r;
split(root,x-1,l,r);
int ans=t[l].size+1;
root=merge(l,r);
return ans;
}
int kth(int k,int p=root){
if(k<1||k>t[p].size)return 2147483647;
while(true){
if(t[t[p].left].size+1==k)break;
else if(k<t[t[p].left].size+1)p=t[p].left;
else{
k-=t[t[p].left].size+1;
p=t[p].right;
}
}return t[p].value;
}
int prev(int x){
int l,r;
split(root,x/*-1*/,l,r);
int ans=kth(t[l].size,l);
root=merge(l,r);
return ans;
}
int next(int x){
int l,r;
split(root,x,l,r);
int ans=kth(1,r);
root=merge(l,r);
return ans;
}
}t;
main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
int n;
scanf("%lld",&n);
int ans;
scanf("%lld",&ans);
t.insert(ans);
for(int i=2;i<=n;i++){
int x;
scanf("%lld",&x);
ans+=min(abs(t.prev(x)-x),abs(t.next(x)-x));
t.insert(x);
}printf("%lld\n",ans);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号