Description
维护一棵初始有 n n 个节点的有根树(根节点为),树上节点编号为 1−n 1 − n ,每个点有一个权值 wi w i 。
支持以下操作:
0ux
0
u
x
询问以
u
u
为根的子树中,严格大于的值的个数。
1ux
1
u
x
把
u
u
节点的权值改成。
2ux
2
u
x
添加一个编号为”当前树中节点数+1”的节点,其父节点为
u
u
,其权值为。
强制在线。
Solution
考虑对时间分块。
先用 dfs d f s 序+划分树(也可以主席树+离散化)预处理,然后开一个队列存储每次的修改。
对于一次询问,如果它是新加进来的点,那么直接在队列中查找对它有贡献的节点即可。否则先统计预处理的答案再考虑修改对询问的影响。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 600005, maxw = (1ll << 31) - 2;
int n, m, w[maxn], lazy[maxn], S;
int que1[maxn], tot1, que2[maxn], tot2, vis[maxn];
int f[maxn][21], dep[maxn];
int dfn[maxn], low[maxn], Time, ord[maxn];
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;
}
namespace segt
{
vector<int> v[maxn];
#define lch (s << 1)
#define rch (s << 1 | 1)
#define mid ((l + r) >> 1)
void build(int s, int l, int r)
{
v[s].clear();
if (l == r) {
v[s].push_back(w[ord[l]]);
return ;
}
build(lch, l, mid);
build(rch, mid + 1, r);
v[s].resize(r - l + 1);
merge(v[lch].begin(), v[lch].end(), v[rch].begin(), v[rch].end(), v[s].begin());
}
int query(int s, int l, int r, int x, int y, int k)
{
if (x <= l && r <= y)
return v[s].end() - upper_bound(v[s].begin(), v[s].end(), k);
int res = 0;
if (x <= mid) res += query(lch, l, mid, x, y, k);
if (y >= mid + 1) res += query(rch, mid + 1, r, x, y, k);
return res;
}
}
struct edge {
int to, next;
} e[maxn * 2];
int h[maxn], tot;
inline void add(int u, int v)
{
e[++tot] = (edge) {v, h[u]}; h[u] = tot;
e[++tot] = (edge) {u, h[v]}; h[v] = tot;
}
void dfs(int u, int fa)
{
ord[dfn[u] = ++Time] = u;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != fa) dfs(v, u);
low[u] = Time;
}
int tag;
void rebuild()
{
Time = 0; ++tag; dfs(1, 0);
segt::build(1, 1, n);
}
inline void getfa(int u, int fa)
{
f[u][0] = fa; dep[u] = dep[fa] + 1;
for (int i = 0; f[u][i]; ++i) f[u][i + 1] = f[f[u][i]][i];
}
inline bool subtree(int u, int v)
{
int p = dep[v] - dep[u];
for (int i = 20; i >= 0; --i)
if (p & (1 << i)) v = f[v][i];
return u == v;
}
void dfs2(int u, int fa)
{
getfa(u, fa);
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != fa) dfs2(v, u);
}
int query(int u, int x)
{
int res = 0;
if (dfn[u])
res = segt::query(1, dfn[1], low[1], dfn[u], low[u], x);
for (int i = 1; i <= tot1; ++i)
if (((lazy[que1[i]] > x) ^ (w[que1[i]] > x)) && subtree(u, que1[i])) {
if (lazy[que1[i]] > x) ++res;
else --res;
}
for (int i = 1; i <= tot2; ++i)
if (w[que2[i]] > x && subtree(u, que2[i]))
++res;
return res;
}
int main()
{
freopen("gty.in", "r", stdin);
freopen("gty.out", "w", stdout);
n = gi();
for (int i = 1; i < n; ++i) add(gi(), gi());
for (int i = 1; i <= n; ++i) w[i] = gi();
rebuild();
dfs2(1, 0);
m = gi(); S = ceil(sqrt(m) * 5);
int opt, u, x, lastans = 0;
while (m--) {
opt = gi(); u = gi(); x = gi();
u ^= lastans; x ^= lastans;
if (x > maxw)
return 1;
if (opt == 0) printf("%d\n", lastans = query(u, x));
else if (opt == 1) {
if (vis[u] != tag) vis[u] = tag, que1[++tot1] = u;
lazy[u] = x;
} else {
que2[++tot2] = ++n; getfa(n, u); add(u, n);
w[n] = x;
}
if (tot1 + tot2 >= S) {
for (int i = 1; i <= tot1; ++i) w[que1[i]] = lazy[que1[i]];
rebuild();
tot1 = tot2 = 0;
}
}
return 0;
}