九校联考-长沙市一中NOIP模拟Day2T3 柱状图(column)

问题描述

WTH 获得了一个柱状图 , 这个柱状图一共有 N 个柱子 , 最开始第 i 根柱子的高度为 x i , 他现在要将这个柱状图排成一个屋顶的形状 , 屋顶的定义如下 :

  1. 屋顶存在一个最高的柱子 , 假设为 i, 最终高度为 h i . 它是所有柱子之中最高的 .
  2. 第 j 根柱子的高度为 h j =h i -|i-j|, 但这个高度必须大于 0, 否则就是不合法的 .

WTH 可以对一个柱子做的操作只有将其高度加一或减一 , WTH 正忙着享受自己的人赢生活于是他将把这个柱状图变成屋顶的任务交给了你 . 你需要求出最少进行多少次操作才能够把这个柱状图变成一个屋顶形状 .

输入

第一行包含一个正整数 N(1 ≤ N≤ 100 000).
第二行包含 N 个用空格隔开的正整数 , 表示 x i , 含义如题面。

输出

输出最少进行多少个操作才能够把这个柱状图变成屋顶的形状。

输入输出样例

样例 1
column.in

4
1 1 2 3

column.out

3

样例 2
column.in

5
4 5 7 2 2

column.out

4

样例的解释 : 例一升高 2,3,4 号柱子一个单位高度是操作最少的方法之一,最高处为第四个柱子。例二降低第三根柱子三个高度 , 升高第四个柱子一个高度。最高处为第 2 个柱子。

数据范围

30%的数据满足:1<=N<= 100。
60%的数据满足:1<=N<= 5000。
100%的数据满足:1<=N<=100000,1<= \(h_i\) <= \(10^9\)

给的代码依然看不懂,学姐的方法是不断的往上加,用平衡树+线段树(不是树套树)维护可以少加的值
然而下面贴的是标程

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define Pi pair<LL,int>
#define mk make_pair
#define fi first
#define se second

const int Maxn = 1e5+5; 
const int inf = 2e9;

inline int read(){
	int x = 0,f = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch <= '9' && ch >= '0')
		x = x*10+ch-'0',ch = getchar();
	return x * f;	
}

int N , rel , rer;
int h[Maxn] ,rkl[Maxn] , rkr[Maxn];
LL ans;

struct data{
	int Pos,x;
	
	bool operator < (const data &A) const{
		return Pos < A.Pos;
	}
}PL[Maxn],PR[Maxn];

struct Bit{
	LL T[Maxn]; int cnt[Maxn];
	
	void upd(int x,int pos,int ct){
		for(int i = x ; i <= N ; i += i&-i)
			T[i] += pos,cnt[i] += ct;
	}
	
	Pi Sum(int x){
		LL tmp = 0; int ret = 0;
		for(int i = x ; i ; i -= i&-i) 
			tmp += T[i],ret += cnt[i];
		return mk(tmp , ret);
	}
	
	Pi Query(int l,int r){
		if(l > r) return mk(0LL , 0);
		Pi L = Sum(l-1),R = Sum(r); 
		return mk(R.fi - L.fi,R.se - L.se); 
	}
}Ri,Le; 

// Right : h[j] + j = h[i] + i 
//Left: h[j] - j = h[i] - i
 
int LB(data *P,int val){
	int mid,l = 1,r = N,ret = 0;
	while(l <= r){
		mid = l + r >> 1;
		if(P[mid].Pos > val) r = mid - 1;
		else ret = mid,l = mid + 1;
	}
	return ret;
} 
 
LL Solve(int x,int H){
	LL ret = abs(H - h[x]),ps = H - x;
	
	int pos = LB(PL , H - x);
	Pi tmp = Le.Sum(pos);
	ret += ps * tmp.se - tmp.fi;
	//if(x == 4 && H == 5) printf("%lld\n %lld %d\n %d\n",ret,tmp.fi,tmp.se,H - x);
	tmp = Le.Query(pos + 1 , N);
	ret += tmp.fi - ps*tmp.se;
	
	pos = LB(PR , H + x);  ps = H + x;
	tmp = Ri.Sum(pos);
	ret += ps * tmp.se - tmp.fi;
	tmp = Ri.Query(pos + 1 , N);
	ret += tmp.fi - ps*tmp.se;
	return ret; 
}
 
int main(){
	freopen("column.in","r",stdin);
	freopen("column.out","w",stdout);
	N = read();
	for(int i = 1 ; i <= N ; ++i) h[i] = read();
	for(int i = 1 ; i <= N ; ++i) 
		PL[i] = (data){h[i]-i,i},PR[i] = (data){h[i]+i,i};
	sort(PL + 1 , PL + N + 1);
	sort(PR + 1 , PR + N + 1);
	ans = 1LL << 60;
	
	for(int i = 1 ; i <= N ; ++i)
		rkl[PL[i].x] = i,rkr[PR[i].x] = i;
	for(int i = 1 ; i <= N ; ++i)
		Ri.upd(rkr[i] , h[i] + i , 1);
	for(int i = 1 ; i <= N ; ++i){
		Ri.upd(rkr[i] , -(h[i] + i),-1);
		int l = max(i , N - i + 1),r = inf,mid;
		while(r - l > 1){
			mid = l + r >> 1;
			rel = Solve(i , mid - 1); rer = Solve(i , mid);
			if(rel >= rer) l = mid;
			else r = mid;
		}
		ans = min(ans , Solve(i , l));
		ans = min(ans , Solve(i , r));
		Le.upd(rkl[i] , h[i] - i , 1); 
	} 
	printf("%lld\n",ans);
	return 0;
}
posted @ 2018-09-22 07:39  smallshulker  阅读(495)  评论(0编辑  收藏  举报