洛谷P2596 书架 splay

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

题意:

给出$n$本书和$m$个操作,按照操作维护序列并输出对应结果。

题解:

一、splay维护序列解法:

建立书本编号对树上节点的映射,对于$Top$和$Bottom$操作,先把其前驱旋到根,后继旋到根的右儿子,目标节点就是根的右儿子的左儿子。记录其节点编号,然后断开,把节点加到树的最前或者最后。对于$Insert$操作,如果是$0$直接忽略,否则与前驱和后继交换编号值和对应映射。对于$Ask$和$Query$操作,就是平衡树值求权值和权值求值的基本操作。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 6e5 + 5;
int hs[MAXN], a[MAXN];
struct Splay
{
	int fa[MAXN], son[MAXN][2], size[MAXN], val[MAXN];
	int sz, rt;
	void init()
	{
		rt = sz = 0;
	}
	void pushup(int x)
	{
		if (x)
		{
			size[x] = 1;
			if (son[x][0])
				size[x] += size[son[x][0]], hs[val[son[x][0]]] = son[x][0];
			if (son[x][1])
				size[x] += size[son[x][1]], hs[val[son[x][1]]] = son[x][1];
		}
	}
	int getson(int x)
	{
		return son[fa[x]][1] == x;
	}
	void con(int x, int y, int z)
	{
		if (x)
			fa[x] = y;
		if (y)
			son[y][z] = x;
	}
	void rotate(int x)
	{
		int fx = fa[x], ffx = fa[fx];
		int fs = getson(x), ffs = getson(fx);
		con(son[x][fs ^ 1], fx, fs);
		con(fx, x, fs ^ 1);
		con(x, ffx, ffs);
		pushup(fx), pushup(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(f) == getson(x) ? f : x);
			rotate(x);
		}
		if (!end)
			rt = x;
	}
	int newnode(int x,int f)
	{
		int root = ++sz;
		fa[root] = f;
		son[root][0] = son[root][1] = 0;
		val[root] = x;
		size[root] = 1;
		return root;
	}
	int build(int f, int l, int r)
	{
		if (l > r)
			return 0;
		int m = (l + r) >> 1;
		int tmp = newnode(a[m], f);
		son[tmp][0] = build(tmp, l, m - 1);
		son[tmp][1] = build(tmp, m + 1, r);
		hs[a[m]] = tmp;
		pushup(tmp);
		return tmp;
	}
	int pre_nxt(int m)
	{
		int now = son[rt][m];
		while (son[now][m ^ 1])
			now = son[now][m ^ 1];
		return now;
	}
	int minmax(int m)
	{
		int now = rt;
		while (son[now][m])
			now = son[now][m];
		return now;
	}
	//work
	void Top_Bot(int id, int m)
	{
		int pos = hs[id];
		splay(pos, rt);
		if (!son[pos][m])
			return;
		if (!son[pos][m ^ 1])
			son[pos][m ^ 1] = son[pos][m], son[pos][m] = 0;
		else
		{
			int tmp = (!m) ? pre_nxt(1) : pre_nxt(0);
			fa[son[rt][m]] = tmp;
			son[tmp][m] = son[rt][m];
			son[rt][m] = 0;
			splay(tmp, rt);
		}
	}
	void insert(int id, int m)
	{
		if (m)
		{
			int pos = hs[id];
			splay(pos, rt);
			int t = m == 1 ? pre_nxt(1) : pre_nxt(0);
			int v1 = val[t], p2 = hs[v1];
			swap(val[pos], val[t]);
			swap(hs[id], hs[v1]);
		}
	}
	int querynum(int x,int rnk)
	{
		int now = x;
		while (1)
		{
			if (!now)
				return 0;
			if (son[now][0] && rnk <= size[son[now][0]])
			{
				now = son[now][0];
				continue;
			}
			if (son[now][0])
				rnk -= size[son[now][0]];
			if (rnk == 1)
			{
				splay(now, rt);
				return now;
			}
			rnk -= 1;
			now = son[now][1];
		}
	}
	int queryrnk(int id)
	{
		int pos = hs[id];
		splay(pos, rt);
		return size[son[rt][0]] + 1;
	}
	void print(int x)
	{
		if (son[x][0])
			print(son[x][0]);
		printf("%d ", val[x]);
		if (son[x][1])
			print(son[x][1]);
	}
};
Splay sp;
int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	//a[1] = 0, a[n + 2] = n + 1;
	for (int i = 2; i <= n + 1; ++i)
		scanf("%d", &a[i]);
	sp.init();
	sp.rt = sp.build(0, 2, n + 1);
	char str[10];
	int x, y;
	for (int i = 1; i <= m; ++i)
	{
		scanf("%s%d", str, &x);
		if (str[0] == 'I')
		{
			scanf("%d", &y);
			sp.insert(x, y);
		}
		else if (str[0] == 'T')
			sp.Top_Bot(x, 0);
		else if (str[0] == 'B')
			sp.Top_Bot(x, 1);
		else if (str[0] == 'A')
			printf("%d\n", sp.queryrnk(x) - 1);
		else if (str[0] == 'Q')
			printf("%d\n", sp.val[sp.querynum(sp.rt, x)]);
		//sp.print(sp.rt);
		//printf("\n");
		
	}
	return 0;
}

 二、splay维护书本权值解法:

使用结构体保存书本的信息,包括书本的编号和权值。开始时按照$1~n$记录书本的权值,并且设$l$和$r$分别为$1$和$n$,对于$Top$操作和$Bottom$操作,先找到书本对应的结点编号,然后$--l$或者$++r$赋给目标节点的权值,然后把原结点删除再插入新结点,$Insert$就是先找到两个结点然后交换权值信息再重新删除和插入。$Ask$和$Query$是基本操作。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1.5e5 + 5;
int id[MAXN];
struct Splay
{
	struct node
	{
		int v, rnk;
		node(int _v, int _rnk) :v(_v), rnk(_rnk) {};
		node(){}
	};
	node val[MAXN];
	int fa[MAXN], son[MAXN][2], size[MAXN];
	int num[MAXN];
	int sz, rt;
	bool cmp(node& a, node& b)
	{
		return a.rnk >= b.rnk;
	}
	void swp(node& a, node& b)
	{
		int tmp = a.rnk;
		a.rnk = b.rnk;
		b.rnk = tmp;
	}
	void pushup(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)
	{
		if (x)
			fa[x] = y;
		if (y)
			son[y][z] = x;
	}
	int getson(int x)
	{
		return son[fa[x]][1] == x;
	}
	void rotate(int x)
	{
		int fx = fa[x], ffx = fa[fx];
		int fs = getson(x), ffs = getson(fx);
		con(son[x][fs ^ 1], fx, fs);
		con(fx, x, fs ^ 1);
		con(x, ffx, ffs);
		pushup(fx), pushup(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;
	}
	void clear(int x)
	{
		val[0].v = son[x][0] = son[x][1] = 0;
		fa[x] = num[x] = size[x] = 0;
		val[0].rnk = 0;
	}
	int newnode(node x, int f)
	{
		int root = ++sz;
		fa[root] = f;
		son[f][cmp(x, val[f])] = root;
		val[root] = x;
		son[root][0] = son[root][1] = 0;
		num[root] = size[root] = 1;
		return root;
	}
	void insert(node x)
	{
		if (!rt)
		{
			rt = newnode(x, 0);
			return;
		}
		int now = rt, f = 0;
		while (1)
		{
			if (x.rnk == val[now].rnk)
			{
				++num[now];
				pushup(now), pushup(f);
				splay(now, rt);
				return;
			}
			f = now, now = son[now][cmp(x, val[now])];
			if(!now)
			{
				int tmp = newnode(x, f);
				pushup(f);
				splay(tmp, rt);
				return;
			}
		}
	}
	void del(int x)
	{
		queryrnk(x);
		if (num[rt] > 1)
		{
			--num[rt], pushup(rt);
			return;
		}
		else if (!son[rt][0] || !son[rt][1])
		{
			int tmp = rt;
			rt = son[rt][0] + son[rt][1];
			fa[rt] = 0;
			clear(rt);
			return;
		}
		else
		{
			int tmp = rt, l = pre();
			splay(l, rt);
			con(son[tmp][1], rt, 1);
			clear(tmp);
			pushup(rt);
			return;
		}
	}
	int pre()
	{
		int now = son[rt][0];
		while (son[now][1])
			now = son[now][1];
		return now;
	}
	int nxt()
	{
		int now = son[rt][1];
		while (son[now][0])
			now = son[now][0];
		return now;
	}
	node querynum(int rnk)
	{
		int now = rt;
		while (1)
		{
			if (son[now][0] && rnk <= size[son[now][0]])
			{
				now = son[now][0];
				continue;
			}
			if (son[now][0])
				rnk -= size[son[now][0]];
			if (rnk <= num[now])
			{
				splay(now, rt);
				return val[now];
			}
			rnk -= num[now];
			now = son[now][1];
		}
	}
	int queryrnk(int x)
	{
		int now = rt, ans = 0;
		while (val[now].rnk != x)
		{
			if (!now)
				return -0x3f3f3f3f;
			if (val[now].rnk < x)
				now = son[now][1];
			else if (val[now].rnk > x)
				now = son[now][0];
		}
		splay(now, rt);
		return size[son[rt][0]];
	}
	// work
	void top_bottom(int x, int y)//x为旧id,y为新id
	{
		queryrnk(x);
		auto tmp = val[rt];
		tmp.rnk = y;
		del(x);
		insert(tmp);
	}
	void ins(int x, int mod)//x为id
	{
		if (mod)
		{
			queryrnk(x);
			auto v1 = val[mod == -1 ? pre() : nxt()], v2 = val[rt];
			id[v1.v] = v2.rnk, id[v2.v] = v1.rnk;
			del(v2.rnk), del(v1.rnk);
			swp(v1, v2);
			insert(v1), insert(v2);
		}
	}
	void init()
	{
		rt = sz = 0;
	}
};
Splay sp;
typedef Splay::node nd;
int main()
{
	int n, m, a, b;
	
	scanf("%d%d", &n, &m);
	sp.init();
	sp.insert(nd(-0x3f3f3f3f, -0x3f3f3f3f));
	sp.insert(nd(0x3f3f3f3f, 0x3f3f3f3f));
	int head = 1, tail = n;
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &a);
		sp.insert(nd(a, i));
		id[a] = i;
	}
	char str[10];
	for (int i = 1; i <= m; ++i)
	{
		scanf("%s%d", str, &a);
		if (str[0] == 'I')
		{
			scanf("%d", &b);
			sp.ins(id[a], b);
		}
		else if (str[0] == 'T')
		{
			int tmp = id[a];
			id[a] = --head;
			sp.top_bottom(tmp, id[a]);
		}
		else if (str[0] == 'B')
		{
			int tmp = id[a];
			id[a] = ++tail;
			sp.top_bottom(tmp, id[a]);
		}
		else if (str[0] == 'A')
			printf("%d\n", sp.queryrnk(id[a]) - 1);
		else if (str[0] == 'Q')
			printf("%d\n", sp.querynum(a + 1).v);
	}
	return 0;
}

 

posted @ 2019-10-09 17:03  Aya_Uchida  阅读(185)  评论(0编辑  收藏  举报