zoukankan      html  css  js  c++  java
  • luogu 3248

    直接向原树加子树是不可能的
    考虑重新建立这样一颗树,我们称之为 S 树
    将每次需要添加的子树看做一个点,称之为 S 点
    新建的树就是由这些点构成的,
    那么树的大小是合理的
    初始节点为整棵原树
    由于添加的子树的节点的编号一定是连续的一段区间
    树上的每个节点维护 l, r, rt
    分别表示 左端点, 右端点, 这棵子树的根在原树上的编号
    定义
    宏观树:只有 S 点构成的树 -> S 树
    微观树:按照题目描述所形成的树,当然这棵树是不会建立出来的
    所有的询问操作都需要微观树的信息
    首先考虑对于任意合法的点 B, 如何找出它在原树上的对应点 b, 显然 b 的值域为 [1, n]
    S 点满足 l, r 单调
    因此首先二分出 B 点在那个 S 点中,
    S 点代表的子树的编号是 [S.l, S.r]
    所以 B 在该子树中的编号的大小次序为第 B - S.l + 1;
    查询区间 k 大 => 主席树
    这样的话只需对原树建立主席树
    查询以 S.rt 为根的子树中编号第 B - S.l + 1 小的编号就是 b
    Link_super 函数是核心
    然后考虑查询时所要维护的东西
    由于查询树上点对之间的距离,所以只需知道深度就可以解决
    维护这么 3 种深度
    deep[] 原树的深度
    Super_dep[] S 树的深度(宏观树)
    Big_deep[] 微观树的深度,当然并不去维护所有存在的点的深度
    Big_deep[] 相当于是维护的宏观树,只不过所有 S 点的 Big_deep[] 都是微观树上 S 的真实深度值
    这里可以这样理解:
    若 Link_super(u, v), u 的值域 [1, n],
    查询的 v 所在 S 树的 S 点的编号为 X;
    S 的当前总数 + 1 为 Y;
    这样的话 Big_deep[y] = Big_deep[x] + Dis(v, X.rt);
    Dis 函数为查询原树上两点之间的距离
    查询时分类讨论

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <string>
    
    using namespace std;
    
    #define LL long long
    
    #define gc getchar()
    inline int read() {int x = 0; char c = gc; while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x;}
    inline LL read_LL() {LL x = 0; char c = gc; while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x;}
    #undef gc
    
    const int N = 5e5 + 10;
    
    int n, m, q;
    int head[N], cnt;
    LL deep[N];
    int Super_node;
    LL total;
    struct Node {int u, v, nxt;} G[N << 1];
    
    inline void Link(int u, int v) {
        G[++ cnt].v = v, G[cnt].nxt = head[u], head[u] = cnt;
    }
    
    int Hjtjs;
    
    struct NOde {
        int fa[N], size[N], topp[N], tree[N], lst[N], rst[N], tree_js, son[N], bef[N];
        int Lson[N << 2], Rson[N << 2], Size[N << 2], Root[N];
        
        void Dfs_1(int u, int F_, int depth) {
            deep[u] = depth, fa[u] = F_, size[u] = 1;
            for(int i = head[u]; ~ i; i = G[i].nxt) {
                if(G[i].v == F_) continue;
                Dfs_1(G[i].v, u, depth + 1);
                size[u] += size[G[i].v];
                if(size[G[i].v] > size[son[u]]) son[u] = G[i].v;
            }
        }
        
        void Dfs_2(int u, int tp) {
            topp[u] = tp, tree[u] = ++ tree_js, lst[u] = tree[u], bef[tree_js] = u;
            if(!son[u]) {rst[u] = tree[u]; return ;}
            Dfs_2(son[u], tp);
            for(int i = head[u]; ~ i; i = G[i].nxt) {if(G[i].v != fa[u] && G[i].v != son[u]) Dfs_2(G[i].v, G[i].v);}
            rst[u] = tree_js;
        }
        
        void Fill(int x, int y) {Lson[x] = Lson[y], Rson[x] = Rson[y], Size[x] = Size[y];}
        
        void Insert(int &rt, int l, int r, int x) {
            Fill(++ Hjtjs, rt);
            rt = Hjtjs;
            Size[rt] ++;
            if(l == r) return ;
            int mid = (l + r) >> 1;
            if(x <= mid) Insert(Lson[rt], l, mid, x);
            else Insert(Rson[rt], mid + 1, r, x);
        }
        
        void Build_tree() {
            Dfs_1(1, 0, 1);
            Dfs_2(1, 1);
            for(int i = 1; i <= n; i ++) {Root[i] = Root[i - 1]; Insert(Root[i], 1, n, bef[i]);}
        }
        
        inline int Lca(int x, int y) {
            int tpx = topp[x], tpy = topp[y];
            while(tpx != tpy) {
                if(deep[tpx] < deep[tpy]) swap(x, y), swap(tpx, tpy);
                x = fa[tpx], tpx = topp[x];
            }
            return deep[x] < deep[y] ? x : y;
        }
        
        inline int Dis(int x, int y) {int lca = Lca(x, y); return deep[x] + deep[y] - 2 * deep[lca];}
        
        int Sec_A(int ljd, int rjd, int l, int r, int k) {
            if(l == r) return l;
            int mid = (l + r) >> 1;
            int imp = Size[Lson[rjd]] - Size[Lson[ljd]];
            if(k <= (Size[Lson[rjd]] - Size[Lson[ljd]])) return Sec_A(Lson[ljd], Lson[rjd], l, mid, k);
            else return Sec_A(Rson[ljd], Rson[rjd], mid + 1, r, k - (Size[Lson[rjd]] - Size[Lson[ljd]]));
        }
        
    } Tree;
    
    struct Node_ {
        #define E exit(0)
        
        struct Node_3 {LL l, r; int rt;} Super_graph[N];
        
        struct Pair {
            // yvan shu zhong de bian hao, fei shu shang
            int Bef_number;
            // chao ji shu de dian de gen , shi yvan shu shang de dian de bian hao
            int Super_rt;
            // chao ji shu de dian de bian hao 
            int Super_number;
        };
        
        int Super_dep[N];
        LL Big_deep[N];
        int f[N][25];
        int fa[N];
        
        Pair Get_information(LL x) {
            int l = 1, r = Super_node, ans;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(x <= Super_graph[mid].r) ans = mid, r = mid - 1;
                else l = mid + 1;
            }
            int nottree = Super_graph[ans].rt;
            int imp = Tree.Sec_A(Tree.Root[Tree.lst[nottree] - 1], Tree.Root[Tree.rst[nottree]], 1, n, x - Super_graph[ans].l + 1);
            return (Pair) {imp, nottree, ans};
        }
    
        void Link_Super(LL u, LL v) {
            Super_node ++;
            Pair Nodev = Get_information(v);
            Super_graph[Super_node].l = total + 1, Super_graph[Super_node].r = total + Tree.size[u], Super_graph[Super_node].rt = u;
            total += Tree.size[u];
            Super_dep[Super_node] = Super_dep[Nodev.Super_number] + 1;
            int a = Nodev.Super_rt, b = Nodev.Bef_number;
            Big_deep[Super_node] = Big_deep[Nodev.Super_number] + Tree.Dis(b, a) + 1;
            f[Super_node][0] = Nodev.Super_number;
            fa[Super_node] = Nodev.Bef_number;
            for(int i = 1; i <= 16; i ++) f[Super_node][i] = f[f[Super_node][i - 1]][i - 1];
        }
        
        int Lca(int x, int y) {
            if(Super_dep[x] < Super_dep[y]) swap(x, y);
            int del = Super_dep[x] - Super_dep[y];
            for(int i = 0; i <= 18; i ++) if((1 << i) & del) x = f[x][i];
            if(x == y) return x;
            for(int i = 18; i >= 0; i --) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
            return f[x][0];
        }
        
        LL Ask(LL x, LL y) {
            Pair Nodex = Get_information(x), Nodey = Get_information(y);
            if(Super_dep[Nodex.Super_number] <= Super_dep[Nodey.Super_number]) swap(Nodex, Nodey);
            if(Nodex.Super_number == Nodey.Super_number) return Tree.Dis(Nodex.Bef_number, Nodey.Bef_number);
            else {
                int lca = Lca(Nodex.Super_number, Nodey.Super_number);
                LL ret;
                if(lca == Nodey.Super_number) {
                    int g = Nodex.Super_number;
                    for(int i = 18; i >= 0; i --) if(f[g][i] && Super_dep[f[g][i]] > Super_dep[lca]) g = f[g][i];
                    ret = Big_deep[Nodex.Super_number] - Big_deep[g] + 1 + Tree.Dis(Nodex.Super_rt, Nodex.Bef_number);
                    ret += Tree.Dis(fa[g], Nodey.Bef_number);
                } else {
                    int a = Nodex.Super_number, b = Nodey.Super_number;
                    for(int i = 18; i >= 0; i --) {if(f[a][i] && Super_dep[f[a][i]] > Super_dep[lca]) a = f[a][i];}
                    for(int i = 18; i >= 0; i --) {if(f[b][i] && Super_dep[f[b][i]] > Super_dep[lca]) b = f[b][i];}
                    ret = Big_deep[Nodex.Super_number] - Big_deep[a] + 1 + Big_deep[Nodey.Super_number] - Big_deep[b] + 1 + Tree.Dis(fa[a], fa[b]);
                    ret += Tree.Dis(Nodex.Super_rt, Nodex.Bef_number) + Tree.Dis(Nodey.Super_rt, Nodey.Bef_number);
                }
                return ret;
            }
        }
        #undef E 
    } S_graph;
    
    int main() {
        n = read(), m = read(), q = read();
        for(int i = 1; i <= n; i ++) head[i] = -1;
        for(int i = 1; i < n; i ++) {int u = read(), v = read(); Link(u, v), Link(v, u);}
        Tree.Build_tree();
        total = n, Super_node = 1;
        S_graph.Super_dep[1] = 1;
        S_graph.f[1][0] = 1;
        S_graph.Super_graph[1].l = 1, S_graph.Super_graph[1].r = n, S_graph.Super_graph[1].rt = 1;
        for(int i = 1; i <= m; i ++) {
            LL x = read_LL(), y = read_LL();
            S_graph.Link_Super(x, y);
        }
        for(int i = 1; i <= q; i ++) {
            LL x = read_LL(), y = read_LL();
            cout << S_graph.Ask(x, y) << "
    ";
        }
    
        return 0;
    }
  • 相关阅读:
    hdu 1023 卡特兰数+高精度
    hdu 1568 Fibonacci 快速幂
    hdu 3054 Fibonacci 找循环节的公式题
    hdu 5167 Fibonacci 打表
    hdu 4165 Pills dp
    HDU 5791 Two DP
    BZOJ 2152: 聪聪可可 树分治
    HDU 5213 Lucky 莫队+容斥
    HDU 5145 NPY and girls 莫队+逆元
    BZOJ 3289: Mato的文件管理 莫队+BIT
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9570337.html
Copyright © 2011-2022 走看看