• [HNOI 2016]树


    Description

    题库链接

    给你一棵 (N) 个节点根节点为 (1) 的有根树,结点的编号为 (1sim N) ;我们称这颗树为模板树。需要通过这棵模板树来构建一颗大树。构建过程如下:

    1. 将模板树复制为初始的大树;
    2. 以下 2.1 2.2 2.3 步循环执行 (M) 次:
      2.1. 选择两个数字 (a,b) ,其中 (1leq aleq N,1leq bleq 当前大树的结点数)
      2.2. 将模板树中以结点 (a) 为根的子树复制一遍,挂到大树中结点 (b) 的下方(也就是说,模板树中的结点 (a) 为根的子树复制到大树中后,将成为大树中结点 (b) 的子树);
      2.3. 将新加入大树的结点按照在模板树中编号的顺序重新编号。大树中这 (C) 个结点编号的大小顺序和模板树中对应的 (C) 个结点的大小顺序是一致的。

    操作结束后 (Q) 组询问,询问两点间的距离。

    (1leq N,M,Qleq 100000)

    Solution

    感觉是 (HNOI~2016) 最简单的题...

    首先发现最坏的情况下有 (N imes M) 个节点;显然不能一个一个节点存下;

    容易想到的就是把每一次操作截下来的子树缩成一个点。我们可以再建一个图来维护操作新建的节点间的关系;

    其次对于节点的编号;其实就是转化成求子树点权的 (K) 大;用 (dfs) 序,将这个问题变成序列求区间 (K) 大。因为同一个子树中的节点的 (dfs) 序是相邻的。用主席树解决。

    然后就是疯狂套模版+询问讨论就好了。鬼知道哪些要开 (long~long) ,就全开了。

    Code

    //It is made by Awson on 2018.3.5
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const LL N = 100000;
    void read(LL &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    LL n, m, q, u, v, lim, size[N+5], opt[N+5][3], sum[N+5], id[N+5], loc;
    struct Segment_tree {
        LL root[N+5], ch[N*50+5][2], key[N*50+5], pos;
        LL cpynode(LL o) {++pos; ch[pos][0] = ch[o][0], ch[pos][1] = ch[o][1], key[pos] = key[o]; return pos; }
        void insert(LL &o, LL l, LL r, LL loc) {
        o = cpynode(o); ++key[o];
        if (l == r) return; LL mid = (l+r)>>1;
        if (loc <= mid) insert(ch[o][0], l, mid, loc); else insert(ch[o][1], mid+1, r, loc);
        }
        LL query(LL a, LL b, LL l, LL r, LL k) {
        if (l == r) return l; LL mid = (l+r)>>1;
        LL tmp = key[ch[b][0]]-key[ch[a][0]];
        if (tmp >= k) return query(ch[a][0], ch[b][0], l, mid, k);
        else return query(ch[a][1], ch[b][1], mid+1, r, k-tmp);
        }
    }T;
    struct graph {
        struct tt {LL to, next, cost; }edge[(N<<1)+5];
        LL path[N+5], top, fa[N+5][20], dep[N+5], dist[N+5];
        void add(LL u, LL v, LL c = 1) {edge[++top].to = v, edge[top].cost = c, edge[top].next = path[u], path[u] = top; }
        void dfs(LL o, LL father, LL depth, LL dst) {
        fa[o][0] = father, dep[o] = depth, dist[o] = dst; for (LL i = 1; i <= lim; i++) fa[o][i] = fa[fa[o][i-1]][i-1];
        for (LL i = path[o]; i; i = edge[i].next)
            if (edge[i].to != father) dfs(edge[i].to, o, depth+1, dst+edge[i].cost);
        }
        LL lca(LL u, LL v) {
        if (dep[u] < dep[v]) Swap(u, v);
        for (LL i = lim; i >= 0; i--) if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
        if (u == v) return u;
        for (LL i = lim; i >= 0; i--) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
        return fa[u][0];
        }
        LL slca(LL u, LL lca) {for (LL i = lim; i >= 0; i--) if (dep[fa[u][i]] > dep[lca]) u = fa[u][i]; return u; }
        LL dis(LL u, LL v) {return dist[u]+dist[v]-(dist[lca(u, v)]<<1); }
        void btree(LL o) {
        id[o] = ++loc;
        T.root[loc] = T.root[loc-1]; T.insert(T.root[loc], 1, n, o); size[o] = 1;
        for (LL i = path[o]; i; i = edge[i].next)
            if (edge[i].to != fa[o][0]) btree(edge[i].to), size[o] += size[edge[i].to];
        }
    }g1, g2;
    
    LL ids(LL u, LL v) {return T.query(T.root[id[opt[u][0]]-1], T.root[id[opt[u][0]]+size[opt[u][0]]-1], 1, n, v-sum[u-1]); }
    LL query(LL a, LL b, LL u, LL v) {
        LL ans = 0, lca = g2.lca(a, b);
        if (a != lca) {
        ans += g1.dis(u, opt[a][0])+1;
        LL t = g2.slca(a, lca); ans += g2.dis(a, t);
        u = ids(lca, opt[t][2]);
        }
        if (b != lca) {
        ans += g1.dis(v, opt[b][0])+1;
        LL t = g2.slca(b, lca); ans += g2.dis(b, t);
        v = ids(lca, opt[t][2]);
        }
        return ans+g1.dis(u, v);
    }
    void work() {
        read(n), read(m), read(q), ++m; lim = log(n)/log(2);
        for (LL i = 1; i < n; i++) read(u), read(v), g1.add(u, v), g1.add(v, u);
        g1.dfs(1, 0, 1, 0); g1.btree(1); opt[1][0] = 1; opt[1][1] = sum[1] = n;
        for (LL i = 2; i <= m; i++) {
        read(opt[i][0]), read(v); opt[i][2] = v; u = lower_bound(sum+1, sum+i, v)-sum;
        LL a = ids(u, v);
        g2.add(u, i, g1.dis(opt[u][0], a)+1);
        opt[i][1] = size[opt[i][0]], sum[i] = sum[i-1]+opt[i][1];
        }
        g2.dfs(1, 0, 1, 0);
        while (q--) {
        read(u), read(v);
        LL a = lower_bound(sum+1, sum+m+1, u)-sum, b = lower_bound(sum+1, sum+m+1, v)-sum;
        writeln(query(a, b, ids(a, u), ids(b, v)));
        }
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    [考试]20150811
    [考试]20150810
    [随笔]暑假过了,暑假来了
    [考试]20150808
    动态规划大合集II
    [知识点][旧版]C++中的运算符
    NOIP动态规划大合集
    [考试]20150729
    [考试]20150728
    /=============分隔线=============/
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8510983.html
Copyright © 2020-2023  润新知