洛谷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; }