P5314 [Ynoi2011] ODT 题解
lxl 说过邻域信息维护父亲一定死,所以考虑对每个点维护其所有儿子构成的平衡树,
发现这样还是不行,于是对每个点维护其所有轻儿子构成的平衡树,
发现这样就可以了,因为每次链加只会修改 $O(\log n)$ 个点的平衡树。
在维护平衡树的过程中需要单点求值,再维护个树状数组即可。
俩 $\log$ 跑 1e6 直接松过去了 /jy
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
inline int R()
{
int q = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
q = q * 10 + c - '0', c = getchar();
return q;
}
struct E
{
int v, t;
} e[2000050];
int n, m, c, _, a[1000050], z[1000050], d[1000050], f[1000050], s[1000050], t[1000050], b[1000050], h[1000050], C[1000050], _C[1000050];
struct T
{
T *l, *r;
int v, k, s;
T(int _v) : l(0), r(0), v(_v), k(rand()), s(1) {}
void p()
{
s = 1;
if (l)
s += l->s;
if (r)
s += r->s;
}
} * r[1000050];
void G(int x, int k)
{
for (; x <= n; x += x & -x)
C[x] += k;
}
int Q(int x)
{
int q = 0;
for (; x; x &= x - 1)
q += C[x];
return q;
}
void A(int u, int v) { e[++c] = {v, h[u]}, h[u] = c; }
void X(int u, int k)
{
s[u] = 1;
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
{
d[v] = d[f[v] = u] + 1;
X(v, u);
s[u] += s[v];
if (s[v] > s[z[u]])
z[u] = v;
}
}
void Y(int u, int g)
{
t[u] = g;
b[u] = ++_;
if (z[u])
Y(z[u], g);
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != f[u] && v != z[u])
Y(v, v);
}
void S(T *x, int k, T *&a, T *&b)
{
if (!x)
return a = b = 0, void();
if (x->v > k)
b = x, S(x->l, k, a, b->l), b->p();
else
a = x, S(x->r, k, a->r, b), a->p();
}
T *M(T *a, T *b)
{
if (!a)
return b;
if (!b)
return a;
if (a->k < b->k)
return a->r = M(a->r, b), a->p(), a;
else
return b->l = M(a, b->l), b->p(), b;
}
void I(T *&r, int v)
{
T *a, *b;
S(r, v, a, b);
r = M(a, M(new T(v), b));
}
void D(T *&r, int v)
{
T *a, *b, *c;
S(r, v, a, c);
S(a, v - 1, a, b);
r = M(a, M(b->l, M(b->r, c)));
delete b;
}
int K(T *x, int v)
{
int z = x->l ? x->l->s : 0;
if (v == z + 1)
return x->v;
if (v <= z)
return K(x->l, v);
else
return K(x->r, v - z - 1);
}
int main()
{
n = R(), m = R();
for (int i = 1; i <= n; ++i)
a[i] = R();
for (int i = 1, u, v; i < n; ++i)
u = R(), v = R(), A(u, v), A(v, u);
X(1, 0);
Y(1, 1);
for (int i = 1; i <= n; ++i)
C[b[i]] += a[i], C[b[i] + 1] -= a[i];
for (int i = 1; i <= n; ++i)
_C[i] = _C[i - 1] + C[i], C[i] = _C[i] - _C[i & i - 1];
for (int u = 1; u <= n; ++u)
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != f[u] && v != z[u])
I(r[u], a[v]);
for (int i = 0, o, x, y, k; i < m; ++i)
{
o = R(), x = R(), y = R();
if (o & 1)
{
k = R();
while (t[x] != t[y])
{
if (d[t[x]] < d[t[y]])
swap(x, y);
D(r[f[t[x]]], Q(b[t[x]]));
G(b[t[x]], k);
G(b[x] + 1, -k);
I(r[f[t[x]]], Q(b[t[x]]));
x = f[t[x]];
}
if (b[x] > b[y])
swap(x, y);
if (f[x] && x == t[x])
D(r[f[x]], Q(b[x]));
G(b[x], k);
G(b[y] + 1, -k);
if (f[x] && x == t[x])
I(r[f[x]], Q(b[x]));
}
else
{
I(r[x], Q(b[x]));
if (f[x])
I(r[x], Q(b[f[x]]));
if (z[x])
I(r[x], Q(b[z[x]]));
printf("%d\n", K(r[x], y));
D(r[x], Q(b[x]));
if (f[x])
D(r[x], Q(b[f[x]]));
if (z[x])
D(r[x], Q(b[z[x]]));
}
}
return 0;
}