[CF1110F] Nearest Leaf

Portal

一棵n个点的有根树,规定一种dfs序,\(m\)次询问一个点\(u\)和一个区间\([l,r]\),求dfs序在这个区间内的叶子中,到\(u\)最小的距离。

n,m≤500000

这题在线直接搞很难搞, 考虑离线.

一开始想到就是按照区间来离线, 把询问挂在某个端点上. 但是没有什么可以利用的性质(比如说要求单调可以单调队列), 所以弃掉.

考虑按照询问点来离线,然后考虑一每条边的贡献, 若果进入了这条边, 那么到外面的距离会增加, 里面的部分会减少. 这样直接用线段树维护就可以了, 实现有点麻烦.

考虑这个问题的扩展, 如果要在线, 考虑主席树(参照CF893F), 对于求某一点到树上某一dfn区间的题目也可以这样离线做(参照BZOJ2159,Crash的文明世界),(HDU5449 RobotDog,还是有点像的).

离线题目就可以应用换根的思想, 利用已经计算的值快速计算其他值, 做树上题目一定要注意这点(*).

说那么多干什么, 不就是暴力么?

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(s) debug("The massage in line %d, Function %s: %s\n", __LINE__, __FUNCTION__, s)
typedef long long LL;
typedef long double LD;
int read() {
    char ch = getchar();
    int x = 0, flag = 1;
    for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1;
    for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;
}
void write(LL x) {
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar(x % 10 + 48);
}

const int Maxn = 500009;
struct edge {
    int to, nxt, w;
}g[Maxn << 2];
int n, q, head[Maxn], e;
LL dis[Maxn], isleaf[Maxn], ans[Maxn];
int size[Maxn];

void add(int u, int v, int w) {
    g[++e] = (edge){v, head[u], w}, head[u] = e;
}

template <int N> struct SGMTtree {
    LL tree[N << 3], add[N << 3];
#define lc(x) ((x) << 1)
#define rc(x) ((x) << 1 | 1)
#define ls rt << 1, l, mid
#define rs rt << 1 | 1, mid + 1, r
    void pushup(int rt) { tree[rt] = min(tree[lc(rt)], tree[rc(rt)]); }
    void pushdown(int rt) {
        if (add[rt]) {
            LL &v = add[rt];
            tree[lc(rt)] += v; tree[rc(rt)] += v;
            add[lc(rt)] += v; add[rc(rt)] += v;
            v = 0;
        }
    }
    void build(int rt, int l, int r) {
        if (l == r) {
            tree[rt] = isleaf[l] ? dis[l] : LLONG_MAX / 2;
            return ;
        }
        int mid = (l + r) >> 1;
        build(ls), build(rs);
        pushup(rt);
    }
    void modify(int rt, int l, int r, int P, int Q, int v) {
        if (P <= l && r <= Q) {
            tree[rt] += v, add[rt] += v;
            return ;
        }
        int mid = (l + r) >> 1; pushdown(rt);
        if (Q <= mid) modify(ls, P, Q, v);
        else if (P >= mid + 1) modify(rs, P, Q, v);
        else modify(ls, P, Q, v), modify(rs, P, Q, v);
        pushup(rt); 
    }
    LL query(int rt, int l, int r, int P, int Q) {
        if (P <= l && r <= Q) return tree[rt];
        int mid = (l + r) >> 1; pushdown(rt);
        if (Q <= mid) return query(ls, P, Q);
        else if (P >= mid + 1) return query(rs, P, Q);
        else return min(query(ls, P, Q), query(rs, P, Q));
    }
#undef lc
#undef rc
#undef ls
#undef rs
};

SGMTtree <Maxn> SGT;

void dfsInit(int u, int pa) {
    isleaf[u] = 1;  size[u] = 1;
    for (int i = head[u]; ~i; i = g[i].nxt) {
        int v = g[i].to;
        if (v != pa) {
            dis[v] = dis[u] + g[i].w, isleaf[u] = 0;
            dfsInit(v, u);
            size[u] += size[v];
        }
    }
}

struct node {
    int l, r, Id;
};
vector <node> qset[Maxn];

void init() {
    clar(head, -1);
    n = read(), q = read();
    rep (i, 2, n) {
        int pa = read(), w = read();
        add(pa, i, w), add(i, pa, w);
    }

    rep (i, 1, q) {
        int u = read(), l = read(), r = read();
        qset[u].push_back((node){l, r, i});
    }

    dfsInit(1, 0);
    SGT.build(1, 1, n);
}

void dfsAnswer(int u, int pa) {
    rep (i, 0, qset[u].size() - 1) {
        node s = qset[u][i];
        ans[s.Id] = SGT.query(1, 1, n, s.l, s.r);
    }
    for (int i = head[u]; ~i; i = g[i].nxt) {
        int v = g[i].to;
        if (v != pa) {
            SGT.modify(1, 1, n, v, v + size[v] - 1, -g[i].w);
            if (v != 1) SGT.modify(1, 1, n, 1, v - 1, g[i].w);
            if (v + size[v] - 1 != n) SGT.modify(1, 1, n, v + size[v], n, g[i].w);
            dfsAnswer(v, u);
            SGT.modify(1, 1, n, v, v + size[v] - 1, g[i].w);
            if (v != 1) SGT.modify(1, 1, n, 1, v - 1, -g[i].w);
            if (v + size[v] - 1 != n) SGT.modify(1, 1, n, v + size[v], n, -g[i].w);
        }
    }
}

void solve() {
    dfsAnswer(1, 0);
    rep (i, 1, q) write(ans[i]), putchar('\n');
}

int main() {
    freopen("CF1110F.in", "r", stdin);
    freopen("CF1110F.out", "w", stdout);

    init();
    solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;
}
posted @ 2019-02-12 14:19 Qrsikno 阅读(...) 评论(...) 编辑 收藏