• 洛谷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
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    Visual Studio 快捷键
    C#编程使用Managed Wifi API连接无线SSID
    C#两种创建快捷方式的方法
    COJ 1059
    [Unity3D]Unity3D游戏开发之鼠标滚轮实现放大缩小
    cloudstack4.4新增功能前瞻
    hdu 4635 Strongly connected (tarjan)
    freemarker声明变量
    Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程
    评教,路上的风景更美
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11643224.html
Copyright © 2020-2023  润新知