Description
Solution
这里写的是 @租酥雨 在考场的写法。
显然,聪明程度的比较具有传递性。所以如果我们可以快速把每个人的聪明程度排序,然后就可以轻易的回答询问了。
考虑按找某种顺序往已经排好的序列添加一个数,满足它的父亲已经被比较了(比如直接按输入顺序)。
比较显然的一种方法是用平衡树维护这个序列,每次往平衡树中添加一个点。但是把一个点插入平衡树需要 O ( l o g n ) O(logn) O(logn)次操作,每次比较是 O ( l o g n ) O(logn) O(logn)的,总复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),加上平衡树的大常数显然无法通过。
考虑优化比较的复杂度。我们为每一个人赋上一个 [ 0 , 1 ] [0,1] [0,1]的实数权值,用这个来表示一个人的聪明程度,新加的人的权值为他前驱后继的平均值。但是直接这样会炸精度,所以我们考虑用替罪羊树,在重构的同时重构把权值平均分配。这样由于平衡树的树高是 O ( l o g n ) O(logn) O(logn)的,所以我们 / 2 /2 /2的次数也是 O ( l o g n ) O(logn) O(logn)的,就不会炸精度了。
至于询问是主席树基本操作就不讲了。
顺便说一句,小兰没有发现柯南家族的人都是一个人就可以繁殖后代吗?
#include <bits/stdc++.h>
using namespace std;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
const int maxn = 500005;
const double alpha = 0.7;
int n, q, fa[maxn], c[maxn];
int rt, lch[maxn], rch[maxn], siz[maxn], cnt, tmp[maxn];
double w[maxn];
void dfs(int u)
{
if (lch[u]) dfs(lch[u]);
tmp[++cnt] = u;
if (rch[u]) dfs(rch[u]);
}
void build(int &u, int l, int r, double wl, double wr)
{
int mid = (l + r) >> 1;
u = tmp[mid]; w[u] = (wl + wr) / 2;
if (l < mid) build(lch[u], l, mid - 1, wl, w[u]); else lch[u] = 0;
if (mid < r) build(rch[u], mid + 1, r, w[u], wr); else rch[u] = 0;
siz[u] = 1 + siz[lch[u]] + siz[rch[u]];
}
void rebuild(int &u, double l, double r) {cnt = 0; dfs(u); build(u, 1, cnt, l, r);}
inline bool cmp(int a, int b)
{
if (c[a] != c[b]) return c[a] > c[b];
else if (fa[a] && fa[b] && fa[a] != fa[b]) return w[fa[a]] < w[fa[b]];
else return a > b;
}
void insert(int &u, int x, double l, double r, bool f)
{
if (!u) return u = x, siz[u] = 1, w[x] = (l + r) / 2, void();
++siz[u];
bool flg = 0;
if (cmp(x, u)) {
flg |= alpha * (siz[lch[u]] + 1) > siz[rch[u]];
insert(lch[u], x, l, w[u], flg);
} else {
flg |= alpha * (siz[rch[u]] + 1) > siz[lch[u]];
insert(rch[u], x, w[u], r, flg);
}
if (flg && !f) rebuild(u, l, r);
}
struct edge
{
int to, next;
} e[maxn];
int h[maxn], rk[maxn], dfn[maxn], low[maxn], T, ecnt;
inline void add(int u, int v) {e[++ecnt] = (edge) {v, h[u]}; h[u] = ecnt;}
struct node
{
int lch, rch, siz;
} s[maxn * 60];
int tot, rt1[maxn], rt2[maxn];
void modify(int &x, int l, int r, int p)
{
++tot; s[tot] = s[x]; ++s[x = tot].siz;
if (l == r) return ;
int mid = (l + r) >> 1;
if (p <= mid) modify(s[x].lch, l, mid, p);
else modify(s[x].rch, mid + 1, r, p);
}
int query(int x, int y, int l, int r, int k)
{
if (l == r) return tmp[l];
int mid = (l + r) >> 1;
if (k > s[s[y].lch].siz - s[s[x].lch].siz) return query(s[x].rch, s[y].rch, mid + 1, r, k - (s[s[y].lch].siz - s[s[x].lch].siz));
else return query(s[x].lch, s[y].lch, l, mid, k);
}
void t_dfs(int u)
{
dfn[u] = ++T;
rt1[u] = rt1[fa[u]]; modify(rt1[u], 1, n, rk[u]);
rt2[T] = rt2[T - 1]; modify(rt2[T], 1, n, rk[u]);
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != fa[u]) t_dfs(v);
low[u] = T;
}
int main()
{
n = gi(); q = gi();
for (int i = 2; i <= n; ++i) add(fa[i] = gi(), i);
for (int i = 1; i <= n; ++i) {
c[i] = gi();
insert(rt, i, 0, 1, 0);
}
rebuild(rt, 0, 1);
for (int i = 1; i <= n; ++i) rk[tmp[i]] = i;
t_dfs(1);
int tp, x;
while (q--) {
tp = gi(); x = gi();
if (tp == 1) printf("%d\n", rk[x]);
else if (tp == 2) printf("%d\n", query(0, rt1[x], 1, n, gi()));
else printf("%d\n", query(rt2[dfn[x] - 1], rt2[low[x]], 1, n, gi()));
}
return 0;
}