# poj 3666 Making the Grade

A straight dirt road connects two fields on FJ’s farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).

You are given N integers A1, … , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . … , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is

| A 1 - B 1| + | A 2 - B 2| + … + | AN - BN |
Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.

Input
* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains a single integer elevation: Ai

Output
* Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.

Sample Input
7
1
3
2
4
5
3
9
Sample Output
3
http://blog.sina.com.cn/s/blog_82a8cba50100tog6.html

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
long long a[101000];
long long n[101000];
long long b[101000];
long long dp[2010][2010];
int main()
{
int n;
while(cin>>n)
{
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
for(int j=1;j<=n;j++)
{
dp[1][j]=a[1]-b[j];
if(dp[1][j]<0)
dp[1][j]=-dp[1][j];
}
long long t;
for(int i=2;i<=n;i++)
{
long long k=dp[(i+1)%2][1];
for(int j=1;j<=n;j++)
{
k=min(dp[(i+1)%2][j],k);
t=a[i]-b[j];
if(t<0) t=-t;
dp[i%2][j]=k+t;
}
}
long long ans=dp[n%2][n];
for(int i=n;i>=1;i--)
ans=min(ans,dp[n%2][i]);
printf("%lld\n",ans );
return 0;
}
}

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define MAXN 2010
int N,v[MAXN],len[MAXN],stk[MAXN];
long long  ans[5];
struct Node
{
int v,l,r,dis;
Node(){}
Node(int _v,int _l,int _r,int _d):
v(_v),l(_l),r(_r),dis(_d) {}
}nn[2][MAXN];

int merge(Node n[],int x,int y) //在这里 x是右，首先右子树为空直接返回子树。
{
if(!x) return y;
if(!y) return x;
if(n[x].v<n[y].v) swap(x,y);  //y是小的那个，树根的大的
n[x].r=merge(n,n[x].r,y); //用树根的右子树与值小的y合并
if(n[n[x].l].dis<n[n[x].r].dis) swap(n[x].l,n[x].r); //更新l长度。
n[x].dis=n[n[x].r].dis+1; //更新树根长度 树根等于右子树+1
return x;
}
void solve(Node n[],int t)
{
int top=0;
for(int i=0;i<N;i++)
{
int ct=1;int id=i;
while(top>0&&n[stk[top-1]].v>n[id].v) //如果上一个树根的平均值大于当前的，要进行合并
{ //当上一个树根的平均值比当前树根大，会一直合并，直到比当前小于等于。
top--;
id=merge(n,stk[top],id); //合并  上一棵树和当前这课树 第一棵树不用合并
if((len[top]+1)/2+(ct+1)/2>(len[top]+ct+1)/2)
id = merge(n,n[id].l,n[id].r); //如果结点多了一个 那么删掉最大点 也就是树根
ct+=len[top];
}
len[top]=ct;
stk[top++]=id;  //保留前面所有正确有序的树根结点。
}
for(int i=0,j=0;i<top;i++)
{
int k=n[stk[i]].v;
while(len[i]--) ans[t]+=abs(v[j++]-k);  //更新结果
}

}
int main()
{
while(~scanf("%d",&N))
{
memset(len,0,sizeof(len));
memset(nn,0,sizeof(nn));
for(int i=0;i<N;i++)
{
cin>>v[i];
nn[0][i]=nn[1][N-i+1]=Node(v[i],0,0,0);
}
ans[0]=ans[1]=0;
for(int i=0;i<2;i++) solve(nn[i],i);
printf("%lld\n",min(ans[0],ans[1]));
}
}