链接
题解
最暴力的想法就是对每个节点维护一个堆,对于每条路径,向不在这条路径上的所有点的堆中插入这条路径的重要度,这肯定会T,考虑用数据结构进行优化。两点之间的路径可以树剖之后用线段树成段更新,但如果通过打 l a z y lazy lazy标记的方法实现成段更新会很麻烦,因为 l a z y lazy lazy标记中要记录每一条路径的信息,下传的时候更是要将每一条路径的信息分别下传,无论时间还是空间都无法接受,这时候就用到了标记永久化的思想,询问的时候只需将从线段树的根节点到该叶节点的路径(也就是所有包含该点的区间)上的值取 m a x max max即可,复杂度 O ( n ( l o g n ) 3 ) O(n(logn)^3) O(n(logn)3).
代码
#include <bits/stdc++.h>
using namespace std;
#define REP(i, n) for (int i = 1; i <= (n); i++)
#define sqr(x) ((x) * (x))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int maxn = 100000 + 100;
// const int maxn = 15;
const int maxm = 200000 + 100;
// const int maxm = 30;
const int maxt = 100 + 5;
const int maxk = 1000 + 10;
typedef long long LL;
typedef long double LD;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
const LL unit = 1LL;
const int INF = 0x3f3f3f3f;
const LL Inf = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-4;
const double inf = 1e15;
const double pi = acos(-1.0);
const LL mod = 1000000007;
inline int read()
{
register char c = getchar();
while (c < '0' || c > '9')
c = getchar();
register int x = 0;
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x;
}
struct Edge
{
int to, next;
};
struct Line
{
int l, r;
bool operator< (const Line &a)const
{
if (l == a.l)
return r < a.r;
return l < a.l;
}
} line[maxn << 1];
struct Graph
{
Edge edge[maxm];
int tot, head[maxn];
void init()
{
tot = 1;
memset(head, 0, sizeof(head));
}
void AddEdge(int u, int v)
{
edge[tot] = (Edge){v, head[u]};
head[u] = tot++;
}
} G;
struct PQ
{
priority_queue<int> q1, q2;
void Push(int x)
{
q1.push(x);
}
void Del(int x)
{
q2.push(x);
}
int Top()
{
while (!q2.empty() && q1.top() == q2.top())
q1.pop(), q2.pop();
return q1.empty() ? -1 : q1.top();
}
} t[maxn << 2];
int n, m, dfs_clock;
int x[maxn << 1], y[maxn << 1], z[maxn << 1];
int dfn[maxn], top[maxn], son[maxn], Size[maxn], fa[maxn], dep[maxn];
void dfs1(int u, int ff)
{
fa[u] = ff;
son[u] = 0;
Size[u] = 1;
dep[u] = dep[ff] + 1;
for (int i = G.head[u]; i; i = G.edge[i].next)
{
int v = G.edge[i].to;
if (v == ff)
continue;
dfs1(v, u);
Size[u] += Size[v];
if (Size[v] > Size[son[u]])
son[u] = v;
}
}
void dfs2(int u, int tp)
{
dfn[u] = ++dfs_clock;
top[u] = tp;
if (!son[u])
return;
dfs2(son[u], tp);
for (int i = G.head[u]; i; i = G.edge[i].next)
{
int v = G.edge[i].to;
if (v == fa[u] || v == son[u])
continue;
dfs2(v, v);
}
}
void Update(int L, int R, int x, int opt, int l, int r, int rt)
{
if (L <= l && r <= R)
{
if (opt)
t[rt].Push(x);
else
t[rt].Del(x);
return;
}
int m = (l + r) >> 1;
if (L <= m)
Update(L, R, x, opt, lson);
if (R > m)
Update(L, R, x, opt, rson);
}
void Happen(int x, int y, int z, int opt)
{
int tt = 0;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x, y);
line[++tt] = (Line){dfn[top[x]], dfn[x]};
x = fa[top[x]];
}
if (dep[x] < dep[y])
swap(x, y);
line[++tt] = (Line){dfn[y], dfn[x]};
sort(line + 1, line + 1 + tt);
int le = 1;
for (int i = 1; i <= tt; ++i)
{
if (le <= line[i].l - 1)
Update(le, line[i].l - 1, z, opt, 1, n, 1);
le = max(le, line[i].r + 1);
}
if(le <= n)
Update(le, n, z, opt, 1, n, 1);
}
int Query(int x, int l, int r, int rt)
{
if (l == r)
return t[rt].Top();
int m = (l + r) >> 1;
int ans = t[rt].Top();
if (x <= m)
ans = max(ans, Query(x, lson));
else
ans = max(ans, Query(x, rson));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
n = read(), m = read();
G.init();
int u, v;
for (int i = 1; i < n; ++i)
{
u = read(), v = read();
G.AddEdge(u, v), G.AddEdge(v, u);
}
dfs1(1, 0);
dfs2(1, 1);
int opt, tmp;
for (int i = 1; i <= m; ++i)
{
opt = read();
if (!opt)
{
x[i] = read(), y[i] = read(), z[i] = read();
Happen(x[i], y[i], z[i], 1);
}
else if (opt == 1)
{
tmp = read();
Happen(x[tmp], y[tmp], z[tmp], 0);
}
else
{
tmp = read();
cout << Query(dfn[tmp], 1, n, 1) << "\n";
}
}
return 0;
}