• [HNOI 2014]世界树


    Description

    题库链接

    给出一棵 (n) 个节点的树, (q) 次询问,每次给出 (k) 个关键点。树上所有的点会被最靠近的关键点管辖,若距离相等则选编号最小的那个。求每个关键点管辖多少个节点。

    (1leq n,q,sum kleq 300000)

    Solution

    构出虚树后,我们能用简单的树形 (dp) 求出每个点离他最近的关键点。大体是做两遍 (dfs) 。第一遍用儿子更新父亲,第二遍用父亲更新儿子。

    处理好这个之后,对于虚树上每个点。他的子树有两种:一个是虚树里的,一个是不在虚树里的。不在虚树里的后代肯定和他共用同一个关键点;

    对于虚树上的一条边 ((u,v)) ,我们需要找到 ((u,v)) 边上的所有点以及他们连出去的块的最近点,更新答案。

    如果 (u, v) 的最近点相同,那么这条边所代表的所有点的最近点肯定就是 (u,v) 的最近点;否则,可以用倍增找到临界点,计算贡献。

    Code

    //It is made by Awson on 2018.2.21
    #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 int N = 300000;
    const int INF = ~0u>>1;
    void read(int &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(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, lim, u, v, fa[N+5][20], dep[N+5], size[N+5], dfn[N+5], times;
    int flag[N+5], lst[N+5], kp[N+5], belong[N+5], dist[N+5], k, q, ans[N+5], S[N+5], top;
    struct graph {
        struct tt {int to, next; }edge[(N<<1)+5];
        int path[N+5], top;
        void add(int u, int v) {edge[++top].to = v, edge[top].next = path[u], path[u] = top; }
        void dfs1(int o, int depth) {
        dep[o] = depth, size[o] = 1, dfn[o] = ++times; for (int i = 1; i <= lim; i++) fa[o][i] = fa[fa[o][i-1]][i-1];
        for (int i = path[o]; i; i = edge[i].next)
            if (dfn[edge[i].to] == 0) fa[edge[i].to][0] = o, dfs1(edge[i].to, depth+1), size[o] += size[edge[i].to];
        }
        void dfs2(int o) {
        belong[o] = 0, dist[o] = INF>>1;
        if (flag[o]) belong[o] = o, dist[o] = 0;
        for (int i = path[o]; i; i = edge[i].next) {
            dfs2(edge[i].to);
            if ((dist[edge[i].to]+dep[edge[i].to]-dep[o] < dist[o]) || (dist[edge[i].to]+dep[edge[i].to]-dep[o] == dist[o] && belong[o] > belong[edge[i].to])) dist[o] = dist[edge[i].to]+dep[edge[i].to]-dep[o], belong[o] = belong[edge[i].to];
        }
        }
        void dfs3(int o) {
        for (int i = path[o]; i; i = edge[i].next) {
            if ((dist[o]+dep[edge[i].to]-dep[o] < dist[edge[i].to]) || (dist[o]+dep[edge[i].to]-dep[o] == dist[edge[i].to] && belong[o] < belong[edge[i].to])) dist[edge[i].to] = dist[o]+dep[edge[i].to]-dep[o], belong[edge[i].to] = belong[o];
            dfs3(edge[i].to);
        }
        }
        void dfs4(int o) {
        int rem = size[o];
        for (int &i = path[o]; i; i = edge[i].next) {
            int x = edge[i].to; for (int j = lim; j >= 0; j--) if (dep[fa[x][j]] > dep[o]) x = fa[x][j];
            rem -= size[x];
            if (belong[edge[i].to] == belong[o]) ans[belong[o]] += size[x]-size[edge[i].to];
            else {
            int v = edge[i].to;
            for (int j = lim; j >= 0; j--)
                if (dep[fa[v][j]] >= dep[o])
                if ((dist[edge[i].to]+dep[edge[i].to]-dep[fa[v][j]] < dist[o]+dep[fa[v][j]]-dep[o]) || (dist[edge[i].to]+dep[edge[i].to]-dep[fa[v][j]] == dist[o]+dep[fa[v][j]]-dep[o] && belong[edge[i].to] < belong[o])) v = fa[v][j];
            ans[belong[o]] += size[x]-size[v];
            ans[belong[edge[i].to]] += size[v]-size[edge[i].to];
            }
            dfs4(edge[i].to);
        }
        ans[belong[o]] += rem;
        }
    }g1, g2;
    bool comp(const int &a, const int &b) {return dfn[a] < dfn[b]; }
    int get_lca(int u, int v) {
        if (dep[u] < dep[v]) Swap(u, v);
        for (int i = lim; i >= 0; i--) if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
        if (u == v) return u;
        for (int i = lim; i >= 0; i--) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
        return fa[u][0];
    }
    
    void work() {
        read(n); lim = log(n)/log(2);
        for (int i = 1; i < n; i++) read(u), read(v), g1.add(u, v), g1.add(v, u);
        g1.dfs1(1, 1); read(q);
        while (q--) {
        read(k); for (int i = 1; i <= k; i++) read(lst[i]), flag[kp[i] = lst[i]] = 1;
        top = g2.top = 0; sort(lst+1, lst+1+k, comp);
        S[++top] = 1;
        for (int i = 1; i <= k; i++) {
            int lca = get_lca(lst[i], S[top]);
            while (dfn[lca] < dfn[S[top]]) {
            if (dfn[lca] >= dfn[S[top-1]]) {
                g2.add(lca, S[top]), --top;
                if (S[top] != lca) S[++top] = lca;
                break;
            }
            g2.add(S[top-1], S[top]), --top;
            }
            if (S[top] != lst[i]) S[++top] = lst[i];
        }
        while (top > 1) g2.add(S[top-1], S[top]), --top;
        g2.dfs2(1), g2.dfs3(1), g2.dfs4(1);
        for (int i = 1; i < k; i++) write(ans[kp[i]]), putchar(' ');
        writeln(ans[kp[k]]);
        for (int i = 1; i <= k; i++) flag[kp[i]] = ans[kp[i]] = 0;
        }
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    5-python基础—获取某个目录下的文件列表(适用于任何系统)
    Automated, Self-Service Provisioning of VMs Using HyperForm (Part 1) (使用HyperForm自动配置虚拟机(第1部分)
    CloudStack Support in Apache libcloud(Apache libcloud中对CloudStack支持)
    Deploying MicroProfile-Based Java Apps to Bluemix(将基于MicroProfile的Java应用程序部署到Bluemix)
    Adding Persistent Storage to Red Hat CDK Kit 3.0 (在Red Hat CDK Kit 3.0添加永久性存储)
    Carve Your Laptop Into VMs Using Vagrant(使用Vagran把您笔记本电脑刻录成虚拟机)
    使用Python生成一张用于登陆验证的字符图片
    Jupyter notebook的安装方法
    Ubuntu16.04使用Anaconda5搭建TensorFlow使用环境 图文详细教程
    不同时区的换算
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8457120.html
Copyright © 2020-2023  润新知