zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    Software Solutions CACHE COHERENCE AND THE MESI PROTOCOL
    CACHE COHERENCE AND THE MESI PROTOCOL
    Multiprocessor Operating System Design Considerations SYMMETRIC MULTIPROCESSORS
    Organization SYMMETRIC MULTIPROCESSORS
    PARALLEL PROCESSING
    1分钟内发送差评邮件
    Secure Digital
    SYMMETRIC MULTIPROCESSORS
    A Taxonomy of Parallel Processor Architectures
    parallelism
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8510983.html
Copyright © 2011-2022 走看看