大视野 1588 Splay入门

//	大视野 1588 Splay入门
//
//	解题思路:
//		其实也没啥好解释的.就是每次在当前序列中
//	找与x的最靠近的值(一个比他大,一个比他小)然后
//	这两者与x的差值的绝对值最小,依次累加,就是我们
//	所要求最后的答案.主要是为了学习Splay这个模板
//      感谢网上的大神<a target=_blank id="lnkBlogLogo" href="http://www.cnblogs.com/kane0526/"><img id="blogLogo" src="http://www.cnblogs.com/Skins/custom/images/logo.gif" alt="返回主页" /></a>我亦青灯杯里少年.挺好理解
//	然而我花了好几天的功夫,才能够把它默写下来.继续
//	加油吧~~~更难的还在后面呢.FIGNTING!!!

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX_N = 50009;
const int INF = 1e9;
struct SplayTree{
	int ch[MAX_N][2],val[MAX_N],pre[MAX_N];

	int size;

	int rt;

	void Init(){
		size = 0;
		NewNode(0,rt,-INF);
		NewNode(rt,ch[rt][1],INF);
	}

	void NewNode(int y,int &x,int v){
		x = ++size;
		pre[x] = y;
		val[x] = v;
		ch[x][0] = ch[x][1] = 0;
	}

	void Insert(int a){
		int x = rt;
		while(ch[x][val[x] < a])
			x = ch[x][val[x] < a];
		NewNode(x,ch[x][val[x]<a],a);
		Splay(size,0);
	}

	void Rotate(int x,int d){ // 旋转的操作还是要靠自己悟,我已经悟了差不多间歇性一个月了 d = 0表示左旋,d = 1右旋
		int y = pre[x];
		ch[y][d^1] = ch[x][d];	
		pre[ch[x][d]] = y;
		pre[x] = pre[y];
		if (pre[y])
			ch[pre[y]][ch[pre[y]][1] == y] = x;
		ch[x][d] = y;
		pre[y] = x;
	}

	void Splay(int x,int goal){ // 将x转到goal,这里特殊在于goal是0.也就是所谓的虚的空节点
		while(pre[x]!=goal){
			if (pre[pre[x]] == goal){ 
				if (ch[pre[x]][0] == x)
					Rotate(x,1);
				else Rotate(x,0);
			}
			else {
				int y = pre[x],z = pre[y];
				if (ch[z][0] == y){
					if (ch[y][0] == x){ // 左一字
						Rotate(y,1);
						Rotate(x,1);
					}else{
						Rotate(x,0); // 左之字
						Rotate(x,1);
					}
				}else {
					if (ch[y][1] == x){ // 右一字
						Rotate(y,0);
						Rotate(x,0);
					}else {
						Rotate(x,1);	// 右之字
						Rotate(x,0);
					}
				}
			}
		}
		if (goal == 0)
			rt = x;
	}

	inline int F_min(int a){ //最靠近a但是>=a
		int x = rt;
		int minv = INF;
		while(x){
			if (val[x] == a)	return a;
			if (val[x] > a)	minv = min(minv,val[x]);
			if (val[x] > a) x = ch[x][0];
			else	x = ch[x][1];
		}
		return minv;
	}
	
	inline int F_max(int a){ // 最靠近a但是<=a
		int x = rt;
		int maxv = -INF;
		while(x){
			if (val[x] == a)	return a;
			if (val[x] < a)	maxv = max(maxv,val[x]);
			if (val[x] < a)	x = ch[x][1];
			else x = ch[x][0];
		}
		return maxv;
	}



}spt;

int main(){
	int n;
	//freopen("1.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		int a;
		spt.Init();
		scanf("%d",&a);
		int ans = a;
		spt.Insert(a);
		while(--n){
			if (scanf("%d",&a) == EOF) a = 0; // 这样写是因为数据有问题

			//printf("a = %d f_max(a) = %d , f_min(a) = %d\n",a,spt.F_max(a),spt.F_min(a));
			int x = min(fabs(a - spt.F_max(a)),fabs(spt.F_min(a) - a));
			ans += x;
		//	printf("%d %d\n",n,x);
			spt.Insert(a);
		}
		printf("%d\n",ans);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值