Black Box题解
题意
有以下两种操作:
a
d
d
(
x
)
add(x)
add(x): 把
x
x
x存入
g
e
t
:
i
+
+
get: i++
get:i++,然后输出第
i
i
i小的数
现在给你一个长为
M
M
M的
a
d
d
add
add操作序列
A
A
A,
N
N
N个时间点序列
B
B
B,要求在每个
B
i
B_i
Bi时执行一次
g
e
t
get
get操作,求输出结果序列
思路
直接按照要求在第
i
i
i个时刻插入一个
a
i
a_i
ai
然后在每个时刻判断是否到了
B
i
B_i
Bi的时间
若是到了,便直接查询第
t
o
t
tot
tot个数,然后
+
+
t
o
t
++tot
++tot
注意事项
找
B
i
B_i
Bi的时候用
w
h
i
l
e
while
while
不一定每个查询都在不同时间
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#define pk putchar(' ')
#define ph puts("")
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
template <class T>
void rd(T &x)
{
x = 0;
int f = 1;
char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
x *= f;
}
template <class T>
void pt(T x)
{
if (x < 0)
putchar('-'), x = (~x) + 1;
if (x > 9)
pt(x / 10);
putchar(x % 10 ^ 48);
}
template <class T>
T Max(T a, T b)
{
return a > b ? a : b;
}
template <class T>
T Min(T a, T b)
{
return a < b ? a : b;
}
using namespace std;
const int INF = 0x3f3f3f3f, N = 1e6 + 5;
int root, ans;
struct node
{
int l, r, v, num, size;
ll rnd;
};
//用结构体存变量:
// l:左孩子,r:右孩子;
// v:该节点的权值;
// num:与该节点权值相同的点的个数;
// size:以该节点为根的子树的节点数;
// rnd:该节点的随机值;
// vo:该节点优先级
struct Treap
{
node t[N];
int tot;
void update(int p)
{
t[p].size = t[t[p].r].size + t[t[p].l].size + t[p].num;
}
//用子节点的值更新父节点的值;
void rt(int &p)
{
int q = t[p].l;
t[p].l = t[q].r;
t[q].r = p;
t[q].size = t[p].size;
update(p);
p = q;
}
void lt(int &p)
{
int q = t[p].r;
t[p].r = t[q].l;
t[q].l = p;
t[q].size = t[p].size;
update(p);
p = q;
}
//基础的左旋右旋操作;
void ins(int &p, int x)
{
if (!p)
{
p = ++tot;
t[p].size = t[p].num = 1;
t[p].v = x;
t[p].rnd = rand();
return;
}
t[p].size++;
if (t[p].v == x)
t[p].num++;
else if (x > t[p].v)
{
ins(t[p].r, x);
if (t[t[p].r].rnd < t[p].rnd)
lt(p);
}
//如果要插入的值比当前节点的值大,就将其插入右子树中,同时如果右节点的随机值比当前节点随机值小
//就要通过左旋来维护堆的性质;
else
{
ins(t[p].l, x);
if (t[t[p].l].rnd < t[p].rnd)
rt(p);
}//理由同上;
}
//删除元素
void del(int &p, int x)
{
if (!p)
return;
if (t[p].v == x)
{
if (t[p].num > 1)
t[p].num--, t[p].size--;
else
{
if (t[p].l == 0 || t[p].r == 0)
p = t[p].l + t[p].r;
else if (t[t[p].l].rnd < t[t[p].r].rnd)
rt(p), del(p,x);
else
lt(p), del(p,x);
}
}
else if (x > t[p].v)
t[p].size--, del(t[p].r, x);
else
t[p].size--, del(t[p].l, x);
}
//插入操作
int fpre(int p, int x)
{
if (!p)
return -INF;
if (t[p].v >= x)
return fpre(t[p].l, x);
else
return Max(t[p].v, fpre(t[p].r, x));
}
//查找前驱;
int fbac(int p, int x)
{
if (!p)
return INF;
if (t[p].v <= x)
return fbac(t[p].r, x);
else
return Min(t[p].v, fbac(t[p].l, x));
}
//查找后继;
int fkey(int p, int x)
{
if (!p)
return 0;
if (t[p].v == x)
return t[t[p].l].size + 1;
if (x > t[p].v)
return t[t[p].l].size + t[p].num + fkey(t[p].r, x);
else
return fkey(t[p].l, x);
}
//查询x数的排名;
int fkth(int p, int x)
{
if (!p)
return 0;
if (x <= t[t[p].l].size)
return fkth(t[p].l, x);
x -= t[t[p].l].size;
if (x <= t[p].num)
return t[p].v;
x -= t[p].num;
return fkth(t[p].r, x);
}
//查询排名为x的数;
}Treap1;
const int M = 3e4 + 5;
int a[M], b[M], m, n, cnt, x;
int main()
{
// freopen("testdata.in", "r", stdin);
// freopen("test.out", "w", stdout);
srand(*new unsigned);
rd(m), rd(n);
for (int i = 1;i <= m; i++)
rd(a[i]);
for (int i = 1;i <= n; i++)
rd(b[i]);
x = 1;
for (int i = 1;i <= m; i++)
{
Treap1.ins(root, a[i]);
while (b[x] == i)
{
x++;
pt(Treap1.fkth(root, ++cnt));
ph;
}
}
return 0;
}