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

浙公网安备 33010602011771号