1. 程式人生 > >[HNOI2004]寵物收養場 BZOJ1208 splay tree

[HNOI2004]寵物收養場 BZOJ1208 splay tree

題目描述

凡凡開了一間寵物收養場。收養場提供兩種服務:收養被主人遺棄的寵物和讓新的主人領養這些寵物。

每個領養者都希望領養到自己滿意的寵物,凡凡根據領養者的要求通過他自己發明的一個特殊的公式,得出該領養者希望領養的寵物的特點值a(a是一個正整數,a<2^31),而他也給每個處在收養場的寵物一個特點值。這樣他就能夠很方便的處理整個領養寵物的過程了,寵物收養場總是會有兩種情況發生:被遺棄的寵物過多或者是想要收養寵物的人太多,而寵物太少。

被遺棄的寵物過多時,假若到來一個領養者,這個領養者希望領養的寵物的特點值為a,那麼它將會領養一隻目前未被領養的寵物中特點值最接近a的一隻寵物。(任何兩隻寵物的特點值都不可能是相同的,任何兩個領養者的希望領養寵物的特點值也不可能是一樣的)如果有兩隻滿足要求的寵物,即存在兩隻寵物他們的特點值分別為a-b和a+b,那麼領養者將會領養特點值為a-b的那隻寵物。

收養寵物的人過多,假若到來一隻被收養的寵物,那麼哪個領養者能夠領養它呢?能夠領養它的領養者,是那個希望被領養寵物的特點值最接近該寵物特點值的領養者,如果該寵物的特點值為a,存在兩個領養者他們希望領養寵物的特點值分別為a-b和a+b,那麼特點值為a-b的那個領養者將成功領養該寵物。

一個領養者領養了一個特點值為a的寵物,而它本身希望領養的寵物的特點值為b,那麼這個領養者的不滿意程度為abs(a-b)。

你得到了一年當中,領養者和被收養寵物到來收養所的情況,請你計算所有收養了寵物的領養者的不滿意程度的總和。這一年初始時,收養所裡面既沒有寵物,也沒有領養者。

輸入輸出格式

輸入格式:

第一行為一個正整數n,n<=80000,表示一年當中來到收養場的寵物和領養者的總數。接下來的n行,按到來時間的先後順序描述了一年當中來到收養場的寵物和領養者的情況。每行有兩個正整數a, b,其中a=0表示寵物,a=1表示領養者,b表示寵物的特點值或是領養者希望領養寵物的特點值。(同一時間呆在收養所中的,要麼全是寵物,要麼全是領養者,這些寵物和領養者的個數不會超過10000個)

輸出格式:

僅有一個正整數,表示一年當中所有收養了寵物的領養者的不滿意程度的總和mod 1000000以後的結果。

輸入輸出樣例

輸入樣例#1: 複製
5                  
0 2                      
0 4                         
1 3
1 2
1 5
輸出樣例#1: 複製
3
注:abs(3-2) + abs(2-4)=3,
最後一個領養者沒有寵物可以領養。


用一顆splay tree維護顧客和寵物;
當然也可以用兩棵樹分別維護;
重點就是尋找前驅和後繼;
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
#include<ctime>
#include<deque>
#include<stack>
#include<functional>
#include<sstream>
//#include<cctype>
//#pragma GCC optimize(2)
using namespace std;
#define maxn 200005
#define inf 0x3f3f3f3f
//#define INF 1e18
#define rdint(x) scanf("%d",&x)
#define rdllt(x) scanf("%lld",&x)
#define rdult(x) scanf("%lu",&x)
#define rdlf(x) scanf("%lf",&x)
#define rdstr(x) scanf("%s",x)
typedef long long  ll;
typedef unsigned long long ull;
typedef unsigned int U;
#define ms(x) memset((x),0,sizeof(x))
const long long int mod = 1e9 + 7;
#define Mod 1000000000
#define sq(x) (x)*(x)
#define eps 1e-3
typedef pair<int, int> pii;
#define pi acos(-1.0)
const int N = 1005;
#define REP(i,n) for(int i=0;i<(n);i++)
typedef pair<int, int> pii;
inline ll rd() {
	ll x = 0;
	char c = getchar();
	bool f = false;
	while (!isdigit(c)) {
		if (c == '-') f = true;
		c = getchar();
	}
	while (isdigit(c)) {
		x = (x << 1) + (x << 3) + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}

ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a%b);
}
ll sqr(ll x) { return x * x; }

/*ll ans;
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (!b) {
		x = 1; y = 0; return a;
	}
	ans = exgcd(b, a%b, x, y);
	ll t = x; x = y; y = t - a / b * y;
	return ans;
}
*/

int n;
struct node {
	int ch[2];
	int val;
	int ff;
}t[maxn<<1];

int rt;
int tot;

void rotate(int x) {
	int y = t[x].ff;
	int z = t[y].ff;
	int k = (x == t[y].ch[1]);
	t[z].ch[y == t[z].ch[1]] = x;
	t[x].ff = z;
	t[y].ch[k] = t[x].ch[k ^ 1];
	t[t[x].ch[k ^ 1]].ff = y;
	t[x].ch[k ^ 1] = y;
	t[y].ff = x;
}

void splay(int x, int aim) {
	while (t[x].ff != aim) {
		int y = t[x].ff;
		int z = t[y].ff;
		if (z != aim) {
			(t[z].ch[0] == y) ^ (t[y].ch[0] == x) ? rotate(x) : rotate(y);
		}
		rotate(x);
	}
	if (aim == 0)rt = x;
}

void Insert(int x) {
	int now = rt, ff = 0;
	while (now&&t[now].val != x) {
		ff = now; now = t[now].ch[t[now].val < x];
	}
	if (now);
	else {
		now = ++tot;
		if (ff)t[ff].ch[t[ff].val < x] = now;
		t[now].ff = ff;
		t[now].ch[0] = t[now].ch[1] = 0;
		t[now].val = x;
	}
	splay(now, 0);
}

void Find(int x) {
	int now = rt;
	if (now == 0)return;
	while (t[now].ch[x > t[now].val] && x != t[now].val) {
		now = t[now].ch[x > t[now].val];
	}
	splay(now, 0);
}

int nxt1(int x, int f) {
	Find(x);
	int now = rt;
	if (t[now].val >= x && f)return now;
	if (t[now].val <= x && !f)return now;
	now = t[now].ch[f];
	while (t[now].ch[f ^ 1])now = t[now].ch[f ^ 1];
	return now;
}

int nxt2(int x, int f) {
	Find(x);
	int now = rt;
	if (t[now].val > x&&f)return now;
	if (t[now].val < x && !f)return now;
	now = t[now].ch[f];
	while (t[now].ch[f ^ 1])now = t[now].ch[f ^ 1];
	return now;
}

void del(int x) {
	int l = nxt2(x, 0);
	int r = nxt2(x, 1);
	splay(l, 0); splay(r, l);// split操作
	t[r].ch[0] = 0;
}


int main()
{
	//ios::sync_with_stdio(0);
	rdint(n);
	int cnt = 0, ans = 0;
	Insert(inf); Insert(-inf);
	REP(i, n) {
		int op, x; rdint(op); rdint(x);
		if (cnt == 0)Insert(x);
		if (cnt > 0) {// 寵物splay樹
			if (op == 0)Insert(x);
			else {
				int tmp1 = t[nxt1(x, 0)].val;//前驅
				int tmp2 = t[nxt1(x, 1)].val;// 後繼
				if (abs(tmp1 - x) <= abs(tmp2 - x)) {
					(ans += abs(tmp1 - x)) %= 1000000; del(tmp1);//刪除節點
				}
				else {
					(ans += abs(tmp2 - x)) %= 1000000; del(tmp2);
				}
			}
		}
		if (cnt < 0) {// 顧客splay樹
			if (op == 1)Insert(x);
			else {
				int tmp1 = t[nxt1(x, 0)].val;
				int tmp2 = t[nxt1(x, 1)].val;
				if (abs(tmp1 - x) <= abs(tmp2 - x)) {
					(ans += (abs(tmp1 - x))) %= 1000000; del(tmp1);
				}
				else {
					(ans += (abs(tmp2 - x))) %= 1000000; del(tmp2);
				}
			}
		}
		cnt = cnt + (op == 0 ? 1 : -1);
	}
	cout << ans << endl;
	return 0;
}