[TJOI2007]书架
题目
网上搜
分析
我们可以认为插入一本书是在树中第 \(k\) 的位置进行插入操作
其中 \(k\) 为这本放入书架后的位置
考虑 \(fhq-treap\) 实现
我们将书编号为 \([0,n-1]\)
那么如果插入的书的位置为 \(k\),实际上是在树中位置为 \(k+1\)
将前 \(k\) 个分裂出来就可以插入,再合并还原即可
询问操作就是查第 \(k\) 位
\(Code\)
#include<cstdio>
#include<algorithm>
#include<ctime>
using namespace std;
const int N = 1e5 + 500;
int n, m, q, rt, tot;
char s[N][20];
struct node{
int ls, rs, siz, val, rnd;
}tr[N];
int read()
{
int res = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9')
res=(res<<3)+(res<<1)+ch-'0', ch = getchar();
return res;
}
void pushup(int p){tr[p].siz = tr[tr[p].ls].siz + tr[tr[p].rs].siz + 1;}
int new_node(int v)
{
static int size = 0;
tr[++size] = node{0, 0, 1, v, rand()};
return size;
}
void split(int p, int k, int &x, int &y)
{
if (!p) x = y = 0;
else{
if (k <= tr[tr[p].ls].siz)
y = p, split(tr[p].ls, k, x, tr[p].ls);
else x = p, split(tr[p].rs, k - tr[tr[p].ls].siz - 1, tr[p].rs, y);
pushup(p);
}
}
int merge(int x, int y)
{
if (!x || !y) return x + y;
if (tr[x].rnd < tr[y].rnd)
{
tr[x].rs = merge(tr[x].rs, y);
pushup(x); return x;
}
else{
tr[y].ls = merge(x, tr[y].ls);
pushup(y); return y;
}
}
void insert(int k, int v)
{
int a, b;
split(rt, k, a, b);
rt = merge(a, merge(new_node(v), b));
}
int kth(int k)
{
int a, b, c, d;
split(rt, k - 1, a, b), split(b, 1, c, d);
merge(a, merge(c, d));
return tr[c].val;
}
int main()
{
srand(time(0));
scanf("%d", &n);
for(register int i = 1; i <= n; ++i) scanf("%s", s[tot++]), insert(i - 1, tot - 1);
scanf("%d", &m);
for(register int i = 1, x; i <= m; ++i) scanf("%s", s[tot++]), insert(x = read(), tot - 1);
scanf("%d", &q);
for(register int i = 1, x; i <= q; ++i) x = read(), printf("%s\n", s[kth(x + 1)]);
}