题目大意
给定序列x。
将xi修改成x’要付出|x’-xi|的代价。
求最小代价使得xi<=xi+1
维护函数
设DP,Fi(x)表示把第i个修改成x使得前i个递增的最小代价。
Fi(x)=|x-xi|+min(Fi-1(1~x))
Fi就是函数嘛,容易观察出还是许多一次函数组成的单调函数。
每次就是加上两段一次函数,那个取min是把斜率大于0的直线改为平板。splay维护即可。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=500000+10,maxd=1e9;
int father[maxn*2],tree[maxn*2][2],kk[maxn*2],adk[maxn*2],L[maxn*2],sta[maxn*2];
ll bb[maxn*2],adb[maxn*2];
int i,j,k,l,t,n,m,tot,root,top;
ll ans;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void mark(int x,int k,ll b){
if (!x) return;
kk[x]+=k;adk[x]+=k;
bb[x]+=b;adb[x]+=b;
}
void clear(int x){
if (adk[x]||adb[x]){
mark(tree[x][0],adk[x],adb[x]);
mark(tree[x][1],adk[x],adb[x]);
adk[x]=adb[x]=0;
}
}
void remove(int x,int y){
top=0;
while (father[x]!=y){
sta[++top]=x;
x=father[x];
}
while (top){
clear(sta[top]);
top--;
}
}
int pd(int x){
return tree[father[x]][1]==x;
}
void rotate(int x){
int y=father[x],z=pd(x);
father[x]=father[y];
if (father[y]) tree[father[y]][pd(y)]=x;
tree[y][z]=tree[x][1-z];
if (tree[x][1-z]) father[tree[x][1-z]]=y;
tree[x][1-z]=y;
father[y]=x;
if (y==root) root=x;
}
void splay(int x,int y){
remove(x,y);
while (father[x]!=y){
if (father[father[x]]!=y)
if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x);
rotate(x);
}
}
/*int find(int x,int y){
if (!x) return 0;
if (y>=L[x]){
int t=find(tree[x][1],y);
if (t) return t;else return x;
}
else return find(tree[x][0],y);
}*/
void changemin(){
int j=0,k=root;
ll l;
while (1){
if (!k) break;
clear(k);
if (kk[k]<=0) k=tree[k][1];
else{
j=k;
k=tree[k][0];
}
}
if (j){
splay(j,0);
L[++tot]=L[j];
l=(ll)kk[j]*L[j]+bb[j];
kk[tot]=0;
bb[tot]=l;
tree[tot][0]=tree[j][0];
if (tree[j][0]) father[tree[j][0]]=tot;
root=tot;
}
}
int main(){
freopen("chen.in","r",stdin);freopen("chen.out","w",stdout);
n=read();
root=tot=1;
L[1]=1;
fo(i,1,n){
t=read();
//k=find(root,t);
j=0;k=root;
while (k){
if (L[k]<=t){
j=k;
k=tree[k][1];
}
else k=tree[k][0];
}
k=j;
splay(k,0);
mark(tree[k][0],-1,t);
mark(tree[k][1],1,-t);
if (L[k]==t){
kk[k]++;
bb[k]-=(ll)t;
}
else{
L[++tot]=L[k];
tree[tot][0]=tree[k][0];
if (tree[k][0]) father[tree[k][0]]=tot;
tree[k][0]=tot;
father[tot]=k;
L[k]=t;
kk[tot]=kk[k]-1;
bb[tot]=bb[k]+(ll)t;
kk[k]++;
bb[k]-=(ll)t;
}
changemin();
}
k=root;
while (tree[k][1]){
clear(k);
k=tree[k][1];
}
ans=(ll)kk[k]*maxd+bb[k];
printf("%lld\n",ans);
}