zoukankan      html  css  js  c++  java
  • 洛谷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
    ", sp.queryrnk(x) - 1);
    		else if (str[0] == 'Q')
    			printf("%d
    ", sp.val[sp.querynum(sp.rt, x)]);
    		//sp.print(sp.rt);
    		//printf("
    ");
    		
    	}
    	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
    ", sp.queryrnk(id[a]) - 1);
    		else if (str[0] == 'Q')
    			printf("%d
    ", sp.querynum(a + 1).v);
    	}
    	return 0;
    }
    
  • 相关阅读:
    复盘:错误理解zuul路径匹配,无法使用zuul
    oracle 查询含clob 字段慢
    Javascript生成二维码(QR)
    那些可以在数据库里做的事:分页与过滤
    小谈Scrum敏捷开发流程
    45个实用的JavaScript技巧、窍门和最佳实践
    编写更好的jQuery代码的建议
    冷门JS技巧
    jQuery编程的最佳实践
    chrome扩展安装图文教程
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11642933.html
Copyright © 2011-2022 走看看