数据结构大杂烩。。
我临结束一个半小时开始写的,没调出来,结束后十分钟才调出来。。
题解
前置知识:树的基本知识(dfs 序,欧拉序),ST 表,线段树,可持久化线段树(主席树)
我是两个 log,我不知道正解复杂度多少。。
考虑将 [ l , r ] [l,r] [l,r] 的点分成三部分,一部分在 p p p 的子树里,一部分不在,却与 p p p 同在 1 1 1 的一个子树里,一部分与 p p p 不在 1 1 1 的一个子树里。
如果 A A A, B ∪ C B\cup C B∪C 两者之内都有点,答案就是 0 0 0。
如果点都在 A A A 内,我们只需要知道 lca ( l ∼ r ) \text{lca}(l\sim r) lca(l∼r) 即可。
如果点都在 B ∪ C B\cup C B∪C 内,且只在 C C C 内,我们也只需要知道 lca ( l ∼ r ) \text{lca}(l\sim r) lca(l∼r) 即可。
接下来只需考虑最后一种情况:没有点在 A A A 中,有一些点在 B B B 中。
然后我们还是要分两种情况:
一种是这样的:
就是 1 到 p 的路径上伸出多条子树里面都有点,那么我们只需要找到那个红色位置(最低的那棵子树)即可。
一种是这样的:
此时我们不仅要知道红色位置,还需要知道 lca ( l ∼ r ) \text{lca}(l\sim r) lca(l∼r)。
总而言之,我们需要知道怎么求最低的那棵子树,以及 lca ( l ∼ r ) \text{lca}(l\sim r) lca(l∼r)。
首先考虑求 lca ( l ∼ r ) \text{lca}(l\sim r) lca(l∼r),这个就比较简单,我们使用线段树维护,在 pushup 的时候需要 O ( 1 ) O(1) O(1) 的求两个点的 lca,我们使用 ST 表维护欧拉序上的最小值即可。这一部分的时间复杂度是 O ( n log n ) O(n\log n) O(nlogn)。
然后考虑求最低的那棵子树,我们倍增(二分)往上跳,然后只需要知道某个点的子树内是否有 l ∼ r l\sim r l∼r 的子树,我们做出 dfs 序,建立以 dfs 序为下标的可持久化权值线段树,对 1 ∼ i 1\sim i 1∼i 的子树我们只需要将 dfn 1 ∼ i \text{dfn}_{1\sim i} dfn1∼i 都标为 1 即可。
我们发现我们也顺带获得了判断 4 种情况的方法。
时间复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)。
代码
全场最慢 我都没 rush 出来,我人没了
常数巨大代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read() {
ll ret = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
return ret;
}
int N, Q;
const int MAXN = 200005;
ll dep[MAXN]; int fa[MAXN][21], dfn[MAXN], siz[MAXN], in[MAXN], rein[MAXN << 1], euler[MAXN << 1], dfncnt, eulercnt;
struct node { int v, next; ll k; } E[MAXN << 1]; int head[MAXN], Elen;
void add(int u, int v, ll k) { ++Elen, E[Elen].v = v, E[Elen].next = head[u], head[u] = Elen, E[Elen].k = k; }
void dfs(int u, int ff) {
fa[u][0] = ff, dfn[u] = ++dfncnt, in[u] = ++eulercnt, rein[eulercnt] = u, euler[eulercnt] = u, siz[u] = 1;
for (int i = 1; i <= 20; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (int i = head[u]; i; i = E[i].next) {
if (E[i].v != ff) {
dep[E[i].v] = dep[u] + E[i].k, dfs(E[i].v, u);
euler[++eulercnt] = u, siz[u] += siz[E[i].v];
}
}
}
int st[MAXN << 1][21];
void buildST() {
for (int i = eulercnt; i >= 1; --i) {
st[i][0] = in[euler[i]];
for (int j = 1; i + (1 << j) - 1 <= eulercnt; ++j) {
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
}
inline int lca(int u, int v) {
if (u == v) return u;
u = in[u], v = in[v];
if (u > v) swap(u, v);
int lg = log2(v - u + 1);
return rein[min(st[u][lg], st[v - (1 << lg) + 1][lg])];
}
namespace T1 {
int ans[MAXN << 2];
#define mid ((l + r) >> 1)
void build(int o, int l, int r) {
if (l == r) ans[o] = l;
else build(o << 1, l, mid), build(o << 1 | 1, mid + 1, r), ans[o] = lca(ans[o << 1], ans[o << 1 | 1]);
}
ll query(int o, int l, int r, int L, int R) {
if (l == L && r == R) return ans[o];
else {
if (R <= mid) return query(o << 1, l, mid, L, R);
else if (L > mid) return query(o << 1 | 1, mid + 1, r, L, R);
else return lca(query(o << 1, l, mid, L, mid), query(o << 1 | 1, mid + 1, r, mid + 1, R));
}
}
};
int sum[MAXN << 5], rt[MAXN], lson[MAXN << 5], rson[MAXN << 5], Tlen;
#define mid ((l + r) >> 1)
void insert(int& o, int l, int r, int rt, int p) {
o = ++Tlen;
if (l == r) sum[o] = sum[rt] + 1;
else {
lson[o] = lson[rt], rson[o] = rson[rt];
if (p <= mid) insert(lson[o], l, mid, lson[rt], p);
else insert(rson[o], mid + 1, r, rson[rt], p);
sum[o] = sum[lson[o]] + sum[rson[o]];
}
}
int query(int o, int l, int r, int L, int R) {
if (l == L && r == R) return sum[o];
else {
if (R <= mid) return query(lson[o], l, mid, L, R);
else if (L > mid) return query(rson[o], mid + 1, r, L, R);
else return query(lson[o], l, mid, L, mid) + query(rson[o], mid + 1, r, mid + 1, R);
}
}
#undef mid
inline int Query(int p, int l, int r) { return query(rt[r], 1, N, dfn[p], dfn[p] + siz[p] - 1) - query(rt[l - 1], 1, N, dfn[p], dfn[p] + siz[p] - 1); }
ll lastans;
int main() {
scanf("%d%d", &N, &Q); int i, u, v, p, l, r; ll k;
for (i = 1; i < N; ++i) scanf("%d%d%lld", &u, &v, &k), add(u, v, k), add(v, u, k);
dfs(1, 0);
buildST();
T1::build(1, 1, N);
for (i = 1; i <= N; ++i) {
insert(rt[i], 1, N, rt[i - 1], dfn[i]);
}
while (Q--) {
scanf("%d%d%d", &p, &l, &r), p ^= lastans, l ^= lastans, r ^= lastans;
k = Query(p, l, r);
if (k == r - l + 1) lastans = dep[T1::query(1, 1, N, l, r)] - dep[p];
else if (k != 0) lastans = 0;
else {
u = p;
for (i = 20; i >= 0; --i) if (dep[fa[u][i]] > 0) u = fa[u][i];
k = Query(u, l, r);
if (k == 0) lastans = dep[p] + dep[T1::query(1, 1, N, l, r)];
else {
u = p;
for (i = 20; i >= 0; --i) {
if (fa[u][i] && Query(fa[u][i], l, r) == 0) u = fa[u][i];
}
u = fa[u][0]; int lc = T1::query(1, 1, N, l, r);
if (dep[lc] < dep[u]) lastans = dep[p] - dep[u];
else lastans = dep[p] + dep[lc] - (dep[u] << 1);
}
}
printf("%lld\n", lastans);
}
return 0;
}