题目链接:BZOJ4538
题目大意
给出一颗树,要求支持三种操作:
1. 声明一个经过树上两点之间路径的带权任务;
2. 取消 t 时刻的任务;
3. 询问不经过
分析
1. 乍一看树剖,其实就是树剖+线段树+堆。
2. 首先我们把操作1取反,即在路径的补集上加任务,那么操作3就变成了所有经过 x 的未取消任务的最大值。
3. 线段树每个节点套一个堆,代表覆盖这整个区间的任务的集合;若任务不足以覆盖整个区间,处理方式和经典线段树一样;询问时询问从线段树第一层一直到最后一层
4. 求补集的话,先把原集合在线段树上的各个左右端点 mark[i] 求出,然后加上端点 0 和端点
上代码
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = + ;
const int M = + ;
int n, m;
inline int read() {
char ch;
int ans = , neg = ;
while (ch = getchar(), ch < '0' || ch > '9')
if (ch == '-') neg = -;
while (ch >= '0' && ch <= '9')
ans = ans * + ch - '0', ch = getchar();
return ans * neg;
}
bool book[M];
vector <int> edge[N];
namespace HLD {
struct Poi { // poi? poi!
int id, val;
Poi() {}
Poi(int a, int b) : id(a), val(b) {}
inline bool operator < (const Poi &a) const {
return val < a.val;
}
}; typedef priority_queue <Poi> HP;
int cntSeg;
#define lc(a) (a << 1)
#define rc(a) (lc(a) | 1)
struct SegTree {
HP H;
int l, r;
} T[N * ];
int fa[N], son[N], size[N], dep[N];
int top[N], plc[N], replc[N];
void dfs1(int a, int par) {
fa[a] = par, size[a] = , dep[a] = dep[par] + ;
for (int i = ; i < edge[a].size(); i++) {
int tmp = edge[a][i];
if (tmp == par) continue;
dfs1(tmp, a), size[a] += size[tmp];
if (size[tmp] > size[son[a]]) son[a] = tmp;
}
}
void dfs2(int a, int up) {
top[a] = up, replc[plc[a] = ++cntSeg] = a;
if (son[a]) dfs2(son[a], up);
for (int i = ; i < edge[a].size(); i++) {
int tmp = edge[a][i];
if (tmp == fa[a] || tmp == son[a]) continue;
dfs2(tmp, tmp);
}
}
void build(int a, int l, int r) {
T[a].l = l, T[a].r = r;
if (l == r) return;
int mid = (l + r) >> ;
build(lc(a), l, mid), build(rc(a), mid + , r);
}
Poi mdf;
void modify(int a, int l, int r) {
if (l > r) return;
if (T[a].l == l && T[a].r == r) {
T[a].H.push(mdf); return;
}
int mid = (T[a].l + T[a].r) >> ;
if (r <= mid) modify(lc(a), l, r);
else if (l > mid) modify(rc(a), l, r);
else modify(lc(a), l, mid), modify(rc(a), mid + , r);
}
int getMax(int a, int p) {
while (!T[a].H.empty() && book[T[a].H.top().id]) T[a].H.pop();
int tmp = T[a].H.empty() ? - : T[a].H.top().val;
if (T[a].l == p && T[a].r == p) return tmp;
int mid = (T[a].l + T[a].r) >> ;
if (p > mid) return max(tmp, getMax(rc(a), p));
else return max(tmp, getMax(lc(a), p));
}
int mark[N];
void decom(int a, int b, int c, int d) {
int cnt = ; mdf = Poi(d, c);
while (top[a] != top[b]) {
if (dep[top[a]] < dep[top[b]]) swap(a, b);
mark[++cnt] = plc[top[a]], mark[++cnt] = plc[a];
a = fa[top[a]];
}
if (dep[a] < dep[b]) swap(a, b);
mark[++cnt] = plc[b], mark[++cnt] = plc[a];
mark[++cnt] = , mark[++cnt] = n + ;
sort(mark + , mark + cnt + );
for (int i = ; i <= cnt; i += )
modify(, mark[i - ] + , mark[i] - );
}
}
void init() {
n = read(), m = read();
for (int i = ; i < n; i++) {
int a = read(), b = read();
edge[a].push_back(b), edge[b].push_back(a);
}
HLD::dfs1(, ), HLD::dfs2(, ), HLD::build(, , n);
}
void figure() {
int a, b, c;
for (int i = ; i <= m; i++) {
switch (read()) {
case :
a = read(), b = read(), c = read();
HLD::decom(a, b, c, i); break;
case :
book[read()] = true; break;
default:
a = HLD::plc[read()];
printf("%d\n", HLD::getMax(, a)); break;
}
}
}
int main() {
init();
figure();
return ;
}
以上