P3242 接水果笔记
好题。
题意
给定一个
有
题解
考虑整体二分。
于是现在问题是:处理每个询问包含了几条给定路径。
考虑
下面讨论
,那么令 为 的路径上倒数第二个点,则充要条件是 。 ,那么充要条件是 。
转化一下就可以变成矩形覆盖问题。
于是现在,一个询问
代码:
code:
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 4E4 + 5, LG = 21;
int n, p, tot, q, L[N], R[N], Ans[N], yf[N][LG], dep[N];
vector <int> G[N];
struct E {
int typ, x, y, w, wtf;
bool operator < (const E &l) const {return w < l.w;}
} e[N];
struct Q {
int x, y, k, id;
} a[N], a1[N], a2[N];
void dfs(int x, int fa) {
L[x] = ++tot;
for (auto v : G[x]) {
if (v == fa) continue;
dep[v] = dep[x] + 1; yf[v][0] = x;
for (int i = 1; i < LG; ++i)
yf[v][i] = yf[yf[v][i - 1]][i - 1];
dfs(v, x);
} R[x] = tot;
}
int glca(int u, int v, bool cao = 0) {
if (cao && u == v) return -1;
if (dep[u] < dep[v]) swap(u, v);
for (int i = LG - 1; i >= 0; --i)
if (dep[u] - (1 << i) >= (cao ? dep[v] + 1 : dep[v])) u = yf[u][i];
if (cao && yf[u][0] == v) return u;
if (u == v) return u;
for (int i = LG - 1; i >= 0; --i)
if (yf[u][i] != yf[v][i]) u = yf[u][i], v = yf[v][i];
return (cao ? u : yf[u][0]);
}
struct kdt {
struct pos {int x[2], val;} po[N << 2], P;
int b[N << 2], cnt, rt[LG], m;
struct node {
int ls, rs, sum;
int L[2], R[2], x[2], val;
} t[N << 2];
void pushup(int x) {
t[x].sum = t[t[x].ls].sum + t[t[x].rs].sum + t[x].val;
for (int k : {0, 1}) {
t[x].L[k] = t[x].R[k] = t[x].x[k];
if (t[x].ls) {
t[x].L[k] = min(t[x].L[k], t[t[x].ls].L[k]);
t[x].R[k] = max(t[x].R[k], t[t[x].ls].R[k]);
}
if (t[x].rs) {
t[x].L[k] = min(t[x].L[k], t[t[x].rs].L[k]);
t[x].R[k] = max(t[x].R[k], t[t[x].rs].R[k]);
}
}
}
int build(int l, int r, int dep) {
int mid = (l + r) >> 1;
nth_element(b + l, b + mid, b + r + 1, [&](int x, int y) {return po[x].x[dep] < po[y].x[dep];});
int x = b[mid]; t[x].x[0] = po[x].x[0];
t[x].x[1] = po[x].x[1]; t[x].val = po[x].val;
if (l < mid) t[x].ls = build(l, mid - 1, dep ^ 1);
if (r > mid) t[x].rs = build(mid + 1, r, dep ^ 1);
return pushup(x), x;
}
void append(int &x) {
if (!x) return ; b[++cnt] = x;
append(t[x].ls); append(t[x].rs);
x = 0;
}
int query(int x) {
if (!x) return 0;
bool flg = 1;
for (int k : {0, 1}) flg &= (t[x].R[k] <= P.x[k]);
if (flg) return t[x].sum;
for (int k : {0, 1}) flg |= (t[x].L[k] > P.x[k]);
if (flg) return 0; flg = 1;
for (int k : {0, 1}) flg &= (t[x].x[k] <= P.x[k]);
return query(t[x].ls) + query(t[x].rs) + flg * t[x].val;
}
void push(int x, int y, int val) {
++m; po[m].x[0] = x; po[m].x[1] = y;
po[m].val = val; b[cnt = 1] = m;
for (int i = 0; i < LG; ++i) {
if (!rt[i]) {rt[i] = build(1, cnt, 0); break;}
else append(rt[i]);
}
}
void push(int lx, int rx, int ly, int ry) {
if (rx < lx || ry < ly) return ;
push(lx, ly, 1);
push(lx, ry + 1, -1);
push(rx + 1, ly, -1);
push(rx + 1, ry + 1, 1);
}
int query(int x, int y) {
P.x[0] = x, P.x[1] = y;
int res = 0;
for (int i = 0; i < LG; ++i) res += query(rt[i]);
return res;
}
void clear() {
for (int i = 0; i < LG; ++i) append(rt[i]);
cnt = m = 0;
}
} t;
void solve(int l, int r, int ql, int qr) {
if (ql == qr) {
for (int i = l; i <= r; ++i)
Ans[a[i].id] = e[ql].w;
return ;
}
int mid = (ql + qr) >> 1, cnt1 = 0, cnt2 = 0; for (int i = ql; i <= mid; ++i) {
int u = e[i].x, v = e[i].y;
if (e[i].typ == 1) {
t.push(1, L[u] - 1, L[v], R[v]);
t.push(R[u] + 1, n, L[v], R[v]);
t.push(L[v], R[v], 1, L[u] - 1);
t.push(L[v], R[v], R[u] + 1, n);
} else t.push(L[u], R[u], L[v], R[v]);
}
for (int i = l; i <= r; ++i) {
int tmp = t.query(L[a[i].x], L[a[i].y]);
if (tmp >= a[i].k) a1[++cnt1] = a[i];
else a[i].k -= tmp, a2[++cnt2] = a[i];
} t.clear();
for (int i = 1; i <= cnt1; ++i)
a[l + i - 1] = a1[i];
for (int i = 1; i <= cnt2; ++i)
a[l + cnt1 + i - 1] = a2[i];
solve(l, l + cnt1 - 1, ql, mid);
solve(l + cnt1, r, mid + 1, qr);
}
signed main(void) {
ios :: sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> p >> q;
for (int i = 1; i < n; ++i) {
int u, v; cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
} dep[1] = 1;
for (int i = 0; i < LG; ++i) yf[1][i] = 1;
dfs(1, 0);
for (int i = 1; i <= p; ++i) {
cin >> e[i].x >> e[i].y >> e[i].w;
if (L[e[i].x] > L[e[i].y]) swap(e[i].x, e[i].y);
e[i].typ = 1 + (glca(e[i].x, e[i].y) != e[i].x);
if (e[i].typ == 1) e[i].x = glca(e[i].x, e[i].y, 1);
}
sort(e + 1, e + 1 + p);
for (int i = 1; i <= q; ++i) {
cin >> a[i].x >> a[i].y >> a[i].k;
a[i].id = i;
if (L[a[i].x] > L[a[i].y]) swap(a[i].x, a[i].y);
} solve(1, q, 1, p);
for (int i = 1; i <= q; ++i) cout << Ans[i] << '\n';
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现