Description
给定一棵树,要求支持一下操作
- 选定一条路径,并给定一个权值。
- 取消选定一条路径。
- 求未经过节点uu的路径中,权值最大的那一个。
Solution
网上有许多线段树+堆的做法,但是查询时都递归到了底层,这不是暴力吗??(不过线段树+堆的做法的正确写法似乎是O(nlog3n)O(nlog3n))
这里介绍一种O(nlog2n)O(nlog2n)的整体二分+树状数组的方法。
对于每个询问,二分答案kk,如果所有权值的路径都覆盖了uu,那么的答案肯定⩽k⩽k,否则⩾k⩾k。
用树状数组维护路径覆盖。对于一条路径(u,v)(u,v),在u,vu,v处+1+1,在lca(u,v)lca(u,v)以及lca(u,v)lca(u,v)的父亲处−1−1。查询经过每个节点的路径数等于其子树和。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200005, maxm = 200005;
int n, m, ans[maxm], val[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;
}
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;
}
struct node {
int opt, a, b, c;
}q[maxm];
int dfn[maxn], low[maxn], Time, siz[maxn], son[maxn], dep[maxn];
void dfs1(int u, int fa)
{
siz[u] = 1; dep[u] = dep[fa] + 1;
for (int v, i = h[u]; v = e[i].to, i; i = e[i].next)
if (v != fa) {
dfs1(v, u); siz[u] += siz[v];
if (siz[son[u]] < siz[v]) son[u] = v;
}
}
int g[maxn], f[maxn];
void dfs2(int u, int fa)
{
dfn[u] = ++Time; f[u] = fa;
if (son[u]) g[son[u]] = g[u], dfs2(son[u], u);
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (v != fa && v != son[u]) g[v] = v, dfs2(v, u);
low[u] = Time;
}
int lca(int u, int v)
{
while (g[u] != g[v]) {
if (dep[g[u]] > dep[g[v]]) u = f[g[u]];
else v = f[g[v]];
}
return dep[u] < dep[v] ? u : v;
}
#define lowbit(x) (x & (-x))
int sum[maxn];
inline void insert(int x, int a)
{
if (!x) return;
while (x <= n) {
sum[x] += a; x += lowbit(x);
}
}
inline int query(int x)
{
int ret = 0;
while (x >= 1) {
ret += sum[x]; x -= lowbit(x);
}
return ret;
}
inline void Insert(int u, int v, int k)
{
insert(dfn[u], k); insert(dfn[v], k); insert(dfn[lca(u, v)], -k); insert(dfn[f[lca(u, v)]], -k);
}
void solve(int qryl, int qryr, int l, int r)
{
if (l == r) {
for (int i = qryl; i <= qryr; ++i) if (q[i].opt == 3) ans[q[i].b] = val[l];
return;
}
int mid = val[(l + r) >> 1], Mid = (l + r) >> 1, cnt1 = 0, cnt2 = 0, cntl = 0;
static node t1[maxm], t2[maxm];
for (int i = qryl; i <= qryr; ++i) {
if (q[i].opt == 1) {
if (q[i].c <= mid) t1[++cnt1] = q[i];
else Insert(q[i].a, q[i].b, 1), ++cntl, t2[++cnt2] = q[i];
} else if (q[i].opt == 2) {
if (q[i].c <= mid) t1[++cnt1] = q[i];
else Insert(q[i].a, q[i].b, -1), --cntl, t2[++cnt2] = q[i];
} else {
int cnt = query(low[q[i].a]) - query(dfn[q[i].a] - 1);
if (cnt >= cntl) t1[++cnt1] = q[i];
else t2[++cnt2] = q[i];
}
}
for (int i = qryl; i <= qryr; ++i)
if (q[i].opt == 1 && q[i].c > mid) Insert(q[i].a, q[i].b, -1);
else if (q[i].opt == 2 && q[i].c > mid) Insert(q[i].a, q[i].b, 1);
for (int i = qryl; i <= qryr; ++i)
if (i < qryl + cnt1) q[i] = t1[i - qryl + 1];
else q[i] = t2[i - qryl - cnt1 + 1];
if (cnt1) solve(qryl, qryl + cnt1 - 1, l, Mid);
if (cnt2) solve(qryl + cnt1, qryr, Mid + 1, r);
}
int main()
{
freopen("network.in", "r", stdin);
freopen("network.out", "w", stdout);
n = gi(); m = gi();
for (int i = 1; i < n; ++i) add(gi(), gi());
dfs1(1, 0);
dfs2(1, 0);
int p = 0, cnt = 0;
for (int opt, t, i = 1; i <= m; ++i) {
opt = gi() + 1;
if (opt == 1) q[i] = (node) {opt, gi(), gi(), val[++cnt] = gi()};
else if (opt == 2) t = gi(), q[i] = q[t], q[i].opt = 2;
else if (opt == 3) q[i] = (node) {opt, gi(), ++p};
}
val[++cnt] = -1; sort(val + 1, val + cnt + 1); cnt = unique(val + 1, val + cnt + 1) - val;
solve(1, m, 1, cnt);
for (int i = 1; i <= p; ++i) printf("%d\n", ans[i]);
return 0;
}