CF536E Tavas on the Path 题解
小清新树剖题。
显然不好直接做,离线下来对 $l$ 扫描线。
时刻保证 $\forall x_i\ge l,s_i=1$,然后每条边的 $s_i$ 只会变化一次。
发现维护的是一个颜色段信息,考虑树剖套线段树。
线段树每个节点上维护前缀 $1$ 的个数,后缀 $1$ 的个数,$1$ 的个数和答案。
注意 push up 时左孩子的后缀 $1$ 和右孩子的前缀 $1$ 形成新段。
#include <cstdio>
#include <algorithm>
#define G int m = p->s + p->t >> 1
using namespace std;
struct E
{
int v, w, t;
} e[200050];
struct S
{
int u, v, l, i;
} k[100050];
pair<int, int> g[100050];
int n, m, c, p, F[100050], K[100050], z[100050], d[100050],
f[100050], s[100050], t[100050], b[100050], h[100050];
bool C(S a, S b) { return a.l < b.l; }
void A(int u, int v, int w)
{
e[++c] = {v, w, h[u]};
h[u] = c;
}
void X(int u)
{
s[u] = 1;
for (int i = h[u], v; i; i = e[i].t)
if (!d[v = e[i].v])
{
f[v] = u;
d[v] = d[u] + 1;
g[v] = {e[i].w, v};
X(v);
s[u] += s[v];
if (s[v] > s[z[u]])
z[u] = v;
}
}
void Y(int u, int g)
{
t[u] = g;
b[u] = ++p;
if (z[u])
Y(z[u], g);
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != z[u] && v != f[u])
Y(v, v);
}
struct T
{
T *l, *r;
int s, t, q, x, y, v;
T(int s, int t) : s(s), t(t) {}
void u()
{
v = l->v + r->v;
x = l->v == l->t - l->s + 1 ? l->v + r->x : l->x;
y = r->v == r->t - r->s + 1 ? r->v + l->y : r->y;
q = l->q + r->q - F[l->y] - F[r->x] + F[l->y + r->x];
}
} * r;
T *U(T *x, T *y)
{
if (!x)
return y;
if (!y)
return x;
T *p = new T(x->s, y->t);
p->l = x;
p->r = y;
p->u();
return p;
}
void B(int s, int t, T *&p)
{
p = new T(s, t);
if (s == t)
return void(p->q = F[p->x = p->y = p->v = 1]);
G;
B(s, m, p->l);
B(m + 1, t, p->r);
p->u();
}
void M(int l, T *p)
{
if (p->s == p->t)
return void(p->q = p->x = p->y = p->v = 0);
G;
if (l <= m)
M(l, p->l);
else
M(l, p->r);
p->u();
}
T *Q(int l, int r, T *p)
{
if (l <= p->s && p->t <= r)
return p;
G;
if (l <= m && r > m)
return U(Q(l, r, p->l), Q(l, r, p->r));
if (l <= m)
return Q(l, r, p->l);
if (r > m)
return Q(l, r, p->r);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i < n; ++i)
scanf("%d", F + i);
for (int i = 1, u, v, w; i < n; ++i)
scanf("%d%d%d", &u, &v, &w), A(u, v, w), A(v, u, w);
X(d[1] = 1);
Y(1, 1);
B(1, n, r);
sort(g + 2, g + n + 1);
for (int i = 0; i < m; ++i)
scanf("%d%d%d", &k[i].u, &k[i].v, &k[i].l), k[i].i = i;
sort(k, k + m, C);
for (int i = 0, j = 1, u, v; i < m; ++i)
{
while (j < n && g[j + 1].first < k[i].l)
M(b[g[++j].second], r);
u = k[i].u;
v = k[i].v;
T *p = 0, *q = 0;
while (t[u] != t[v])
{
if (d[t[u]] > d[t[v]])
p = U(Q(b[t[u]], b[u], r), p), u = f[t[u]];
else
q = U(Q(b[t[v]], b[v], r), q), v = f[t[v]];
}
if (u != v)
{
if (d[u] > d[v])
p = U(Q(b[v] + 1, b[u], r), p);
else
q = U(Q(b[u] + 1, b[v], r), q);
}
if (p)
p = new T(*p), swap(p->x, p->y);
K[k[i].i] = U(p, q)->q;
}
for (int i = 0; i < m; ++i)
printf("%d\n", K[i]);
return 0;
}