洛谷P2286 宠物收养场 splay

网址:https://www.luogu.org/problem/P2286

题意:

宠物店会来宠物和客人,且保证同一时刻在宠物店的只有宠物或者客人,如果来的是客人且其目标值为$b$,则其会选择最接近$b$的宠物值$a$,如果有两个满足要求的,会选小的。如果来的是宠物,其值为$a$,就会选择目标值最靠近的客户,如果有多种可能,选小的。求这些客人领养到的宠物的值的和对$1000000$的模。

题解:

因为题目保证了同一时刻在宠物店的只有宠物或者客人,所以我们可以维护一个$cnt$表示当前$splay$的状态,$cnt$初始值为$0$,来的是宠物就$++cnt$,客人就$--cnt$,根据正负就可以判断是客人树还是宠物树。如果是宠物树,当下一个是宠物时则直接插入$splay$,如果是客人则取走宠物(即累加宠物值和删除宠物)。客人树时同理。不在$splay$中的值查找前驱和后继时,有两种方法,一个是插入,寻找前驱后继再删除,一个是直接查找。本题使用第一种,但是第二种更优。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1.2e5 + 5;
#define ll long long
struct Splay
{
	int rt, sz;
	int fa[MAXN], son[MAXN][2], size[MAXN], num[MAXN];
	ll val[MAXN];
	//private
	int getson(int x)
	{
		return son[fa[x]][1] == x;
	}
	void up(int x)
	{
		if (x)
		{
			size[x] = num[x];
			if (son[x][0])
				size[x] += size[son[x][0]];
			if (son[x][1])
				size[x] += size[son[x][1]];
		}
	}
	void con(int x, int y, int z)//x成为y的z儿子
	{
		if (x)
			fa[x] = y;
		if (y)
			son[y][z] = x;
	}
	void rotate(int x)
	{
		int fx = fa[x], ffx = fa[fx];
		int ffs = getson(fx), fs = getson(x);
		con(son[x][fs ^ 1], fx, fs);
		con(fx, x, fs ^ 1);
		con(x, ffx, ffs);
		up(fx), up(x);
	}
	void splay(int x, int end)
	{
		end = fa[end];
		int f;
		while (fa[x] != end)
		{
			f = fa[x];
			if (fa[f] != end)
				rotate(getson(x) == getson(f) ? f : x);
			rotate(x);
		}
		if (!end)
			rt = x;
	}
	int newnode(ll x, int f)
	{
		int nrt = ++sz;
		val[nrt] = x;
		fa[nrt] = f;
		son[f][x > val[f]] = nrt;
		size[nrt] = num[nrt] = 1;
		son[nrt][0] = son[nrt][1] = 0;
		return nrt;
	}
	int pre()
	{
		if (num[rt] > 1)
			return rt;
		int now = son[rt][0];
		while (son[now][1])
			now = son[now][1];
		splay(now, rt);
		return now;
	}
	int nxt()
	{
		if (num[rt] > 1)
			return rt;
		int now = son[rt][1];
		while (son[now][0])
			now = son[now][0];
		splay(now, rt);
		return now;
	}
	//public
	void clear(int x)
	{
		fa[x] = son[x][0] = son[x][1] = size[x] = num[x] = val[x] = 0;
	}
	void insert(ll x)
	{
		if (!rt)
		{
			rt = newnode(x, 0);
			return;
		}
		int now = rt, f = 0;
		while (1)
		{
			if (x == val[now])
			{
				++num[now];
				up(now), up(f);
				splay(now, rt);
				return;
			}
			f = now;
			now = son[now][x > val[now]];
			if (!now)
			{
				int tmp = newnode(x, f);
				up(f);
				splay(tmp, rt);
				return;
			}
		}
	}
	int queryrnk(ll x)
	{
		int ans = 0, now = rt;
		while (1)
		{
			if (x < val[now])
			{
				now = son[now][0];
				continue;
			}
			ans += size[son[now][0]];
			if (x == val[now])
			{
				splay(now, rt);
				return ans + 1;
			}
			ans += num[now];
			now = son[now][1];
		}
	}
	void del(ll x)
	{
		queryrnk(x);
		if (num[rt] > 1)
		{
			--num[rt], up(rt);
			return;
		}
		else if (!son[rt][0] && !son[rt][1])
		{
			clear(rt), rt = 0;
			return;
		}
		else if (!son[rt][0])
		{
			int tmp = rt;
			rt = son[rt][1], fa[rt] = 0;
			clear(tmp);
			return;
		}
		else if (!son[rt][1])
		{
			int tmp = rt;
			rt = son[rt][0], fa[rt] = 0;
			clear(tmp);
			return;
		}
		else
		{
			int tmp = rt, l = pre();
			splay(l, rt);
			con(son[tmp][1], rt, 1);
			clear(tmp);
			up(rt);
			return;
		}
	}
	ll queryfront(ll x)
	{
		insert(x);
		ll tmp = val[pre()];
		del(x);
		return tmp;
	}
	ll queryback(ll x)
	{
		insert(x);
		ll tmp = val[nxt()];
		del(x);
		return tmp;
	}
};
Splay sp;
int mod = 1000000;
int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int n;
	scanf("%d", &n);
	int c, val;
	sp.insert(1ll << 50);
	sp.insert((1ll << 50) * (-1));
	int cnt = 0;
	ll ans = 0;
	for (int i = 0; i < n; ++i)
	{
		scanf("%d%d", &c, &val);
		if (cnt == 0)
			sp.insert(val);
		else if (cnt > 0)
		{
			if (c == 0)
				sp.insert(val);
			else
			{
				ll ans1 = sp.queryfront(val), ans2 = sp.queryback(val);
				if (abs(val - ans1) <= abs(val - ans2))
				{
					sp.del(ans1);
					ans = (ans + abs(val - ans1)) % mod;
				}
				else if (abs(val - ans1) > abs(val - ans2))
				{
					sp.del(ans2);
					ans = (ans + abs(val - ans2)) % mod;
				}
			}
		}
		else if (cnt < 0)
		{
			if (c == 1)
				sp.insert(val);
			else
			{
				ll ans1 = sp.queryfront(val), ans2 = sp.queryback(val);
				if (abs(val - ans1) <= abs(val - ans2))
				{
					sp.del(ans1);
					ans = (ans + abs(val - ans1)) % mod;
				}
				else if (abs(val - ans1) > abs(val - ans2))
				{
					sp.del(ans2);
					ans = (ans + abs(val - ans2)) % mod;
				}
			}
		}
		cnt += c ? -1 : 1;
	}
	printf("%lld\n", ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Aya-Uchida/p/11643224.html
今日推荐