P3850 [TJOI2007]书架
知识点: 平衡树
原题面
题目要求:
给定一长度为 \(n\) 的序列。
支持 \(m\) 次单点插入,\(q\)次 单点查询。
\(1\le N\le 200, 1 \le M \le 10^5,1\le M\le 10^5\)
分析题意
是道水题。
平衡树结构 维护权值在序列中的排名。
现有一数列 1 9 2 6 0 8 1' 7
如图,图中节点上的数 为权值。
平衡树结构 维护权值在序列中的排名。
将平衡树中序遍历后 即可得原序列。
将某节点旋转至根节点后,
由中序遍历的性质, 某节点权值在原序列中的位置,
为总节点数 \(-\) 其右子树大小。
如 8 在原序列中的位置 \(6 = 8 - 2\)。
由性质,则可在平衡树上 dfs。
以k为初始值,不断减去左子树大小,即可求得 原排名为k的权值。
将w插入至k位置,即将w置于 排名为k-1的权值之后,成为它的后继。
在平衡树中,即令w成为 排名为k-1的权值为根的子树 右子树中最左侧的结点。
代码实现时插入了空节点"Marisa" 代表排名为0的节点 (无歧义)。
代码实现
Splay
//Splay
/*
By:Luckyblock
Typical Splay
*/
#include <cstdio>
#include <string>
#include <ctype.h>
#include <iostream>
#include <algorithm>
#define Fat (t[now].Fa)
#define ls (t[now].Son[0])
#define rs (t[now].Son[1])
#define ll long long
const int MARX = 1e6 + 10;
//=============================================================
struct SplayNode {
int Fa, Son[2], Size;
std :: string Val;
} t[MARX];
int N, M, Q, NodeNum, Root;
//=============================================================
inline int read() {
int s = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') s = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
return s * w;
}
bool GetSonNum(int now) {
return t[Fat].Son[1] == now;
}
void Pushup(int now) {
if (now) {
t[now].Size = 1;
if (ls) t[now].Size += t[ls].Size;
if (rs) t[now].Size += t[rs].Size;
}
}
void Rotate(int now) {
int fa = Fat, gfa = t[fa].Fa, WhichSon = GetSonNum(now);
t[fa].Son[WhichSon] = t[now].Son[WhichSon ^ 1];
t[t[fa].Son[WhichSon]].Fa = fa;
t[now].Son[WhichSon ^ 1] = fa;
t[fa].Fa = now, t[now].Fa = gfa;
if (gfa) t[gfa].Son[t[gfa].Son[1] == fa] = now;
Pushup(fa), Pushup(now);
}
void Splay(int now) {
for (int fa = Fat; (fa = Fat) != 0; Rotate(now))
if (t[fa].Fa) Rotate((GetSonNum(now) == GetSonNum(fa)) ? fa : now);
Root = now;
}
int Kth(int rank) {
int now = Root;
while(1) {
if (ls && rank <= t[ls].Size) {
now = ls;
} else {
int tmp = (ls ? t[ls].Size : 0) + 1;
if (rank <= tmp) return now;
rank -= tmp; now = rs;
}
}
}
void Insert(std :: string val, int rank) {
Splay(Kth(rank - 1));
int now = t[Root].Son[1];
if (! now) {
t[++ NodeNum] = (SplayNode) {Root, 0, 0, 1, val};
t[Root].Son[1] = NodeNum;
Splay(NodeNum);
return ;
}
while (t[now].Son[0]) {
now = t[now].Son[0];
}
t[++ NodeNum] = (SplayNode) {now, 0, 0, 1, val};
t[now].Son[0] = NodeNum;
Splay(NodeNum);
}
//=============================================================
int main() {
t[++ NodeNum] = (SplayNode) {0, 0, 0, 1, "Marisa"};
Root = NodeNum;
N = read();
for(int i = 1; i <= N; ++ i) {
std :: string val; std :: cin >> val;
Insert(val, i + 1);
}
M = read();
for (int i = 1; i <= M; ++ i) {
std :: string val; std :: cin >> val;
int rank = read() + 2;
Insert(val, rank);
}
Q = read();
for (int i = 1; i <= Q; ++ i) {
int rank = read();
std :: cout << t[Kth(rank + 2)].Val << "\n";
}
return 0;
}
Fhq-Treap
直接按子树大小分裂即可。
//fhq-treap
/*
By:Luckyblock
*/
#include <cstdio>
#include <string>
#include <cstdlib>
#include <ctype.h>
#include <iostream>
#define ll long long
const int MARX = 2e5 + 10;
//=============================================================
struct FhqTreapNode
{
int son[2], size, Rand;
std :: string val;
} t[MARX];
int NodeNum, Root;
int tmp1, tmp2, tmp3;
//=============================================================
inline int read()
{
int f = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Update(int x) {t[x].size = t[t[x].son[0]].size + t[t[x].son[1]].size + 1;}
int NewNode(std :: string Val)
{
NodeNum ++;
t[NodeNum].size = 1; t[NodeNum].val = Val; t[NodeNum].Rand = rand();
return NodeNum;
}
int Merge(int x, int y)
{
if(! x || ! y) return x + y;
if(t[x].Rand < t[y].Rand)
{
t[x].son[1] = Merge(t[x].son[1], y); Update(x);
return x;
}
t[y].son[0] = Merge(x, t[y].son[0]); Update(y);
return y;
}
void Split(int now, int Size, int &x, int &y)
{
if(! now) {x = y = 0; return ;}
if(Size <= t[t[now].son[0]].size) y = now, Split(t[now].son[0], Size, x, t[now].son[0]);
else x = now, Split(t[now].son[1], Size - t[t[now].son[0]].size - 1, t[now].son[1], y);
Update(now);
}
int Kth(int now, int Rank)
{
while(1)
{
if(Rank <= t[t[now].son[0]].size) {now = t[now].son[0]; continue;}
if(Rank == t[t[now].son[0]].size + 1) return now;
Rank -= t[t[now].son[0]].size + 1, now = t[now].son[1];
}
}
void Insert(int Size, std :: string Val)
{
Split(Root, Size, tmp1, tmp2);
Root = Merge(Merge(tmp1, NewNode(Val)), tmp2);
}
//=============================================================
int main()
{
srand(114514);
int N = read();
for(int i = 1; i <= N; ++ i)
{
std :: string Val; std :: cin >> Val;
Insert(i, Val);
}
int M = read();
for(int i = 1; i <= M; ++ i)
{
std :: string Val; int Pos;
std :: cin >> Val; std :: cin >> Pos;
Insert(Pos, Val);
}
int Q = read();
for(int i = 1; i <= Q; ++ i)
{
int Pos = read() + 1;
std :: cout << t[Kth(Root, Pos)].val << '\n';
}
return 0;
}
作者@Luckyblock,转载请声明出处。