BZOJ 1588 营业额统计【HNOI2002】

题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=1588

水题,查询已有的x的前驱和后继,取差值最小即可。就是数据有点问题,具体看讨论版吧。Splay的效率捉急啊。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n,cnt;

const int inf = 2147483645;

long long ans = 0;

struct Node {
	int val;
	Node *fa,*ch[2];
}*root,*null,T[10000000+10];

Node* Newnode(Node *f,int val) {
	T[cnt].fa = f;T[cnt].val = val;T[cnt].ch[0] = T[cnt].ch[1] = null;return &T[cnt++];
}

void Rotate(Node *u) {
	Node *x = u -> fa,*y = x -> fa;int v = u == x -> ch[1];
	u -> fa = y;if(y != null)y -> ch[x == y -> ch[1]] = u;
	x -> ch[v] =  u -> ch[v^1];if(u -> ch[v^1] != null)u -> ch[v^1] -> fa = x;
	x -> fa = u;u -> ch[v^1] = x;
}

void Splay(Node *u,Node *f) {
	Node *x;
	for(;(x = u -> fa) != f;Rotate(u))if(x -> fa != f)Rotate((u == x -> ch[1]) == (x == x -> fa -> ch[1]) ? x : u);
	if(f == null)root = u;
}

void init() {
	null = Newnode(null,0);root = Newnode(null,inf);root -> ch[0] = Newnode(root,-inf);
}

Node* Find_front(int x) {
	Node *u = root,*ret;int rr = -inf-1;
	while(u != null) {
		if(u -> val > x)u = u -> ch[0];
		else {
			if(u -> val > rr) {
				rr = u -> val;ret = u;
			}
			u = u -> ch[1];
		}
	}
	return ret;
}

Node* Find_back(int x) {
	Node *u = root,*ret;int rr = inf+1;
	while(u != null) {
		if(u -> val < x)u = u -> ch[1];
		else {
			if(u -> val < rr) {
				rr = u -> val;ret = u;
			}
			u = u -> ch[0];
		}
	}
	return ret;
}

long long Get(int x) {
	Node *L = Find_front(x),*R = Find_back(x);
	long long ret;
	if(L -> val == -inf)ret = R -> val - 1LL * x;
	else if(R -> val == inf)ret = 1LL * x - L -> val;
	else ret = min(R -> val - 1LL * x,1LL * x - L -> val);
	if(ret != 0) {
		Splay(R,null);Splay(L,root);Node *u = (root -> ch[0] -> ch[1] = Newnode(root -> ch[0],x));Splay(u,null);
	}
	return ret;
}

int main() {
	init();int x;
	scanf("%d",&n);
	scanf("%d",&x);
	ans += x;root -> ch[0] -> ch[1] = Newnode(root -> ch[0],x);
	for(int i = 1; i < n; i++) {
		if(scanf("%d",&x) == EOF)x = 0;
		ans += Get(x);
	}
	printf("%lld\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值