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;
}
posted @ 2023-02-27 08:10  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源