• 【题解】HNOI2014世界树


      脑子不清醒的时候千万别写题。写题写不下去了千万别死扛,重构才是你唯一的出路QAQ

      昨天很想快点写道题,思路没有很清晰的时候就写了,结果……今天一怒之下决定重整思路重构代码,其实不过是半个小时的事情……

      提示很明显,总点数限制了范围。建立出虚树,在虚树上面 dp。 在虚树上面我们dp两遍,两遍一起处理出每一个(虚树上的)节点被谁管辖,在连接两者的路径上找到管理的分界点即可。处理两点之间的距离一定要上 ST 表啊……

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 350000
    #define CNST 20
    int n, dep[maxn], gra[maxn][CNST];
    int size[maxn], hson[maxn], ans[maxn];
    int top, S[maxn], a[maxn], b[maxn];
    int timer, dfn[maxn], sum[maxn];
    bool mark[maxn], vis[maxn];
    int T, Log[maxn * 2], bit[21], ST[maxn * 2][CNST], pos[maxn];

    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }

    struct edge
    {
        int cnp, to[maxn * 2], last[maxn * 2], head[maxn];
        edge() { cnp = 1; }
        void add(int u, int v)
        {
            if(u == v) return;
            to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
            to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
        }
    }E1, E2;

    bool cmp(int x, int y) { return dfn[x] < dfn[y]; }

    void dfs(int u, int fa)
    {
        size[u] = 1; dfn[u] = ++ timer;
        gra[u][0] = fa; dep[u] = dep[fa] + 1; ST[++ T][0] = dep[u]; pos[u] = T;
        for(int i = 1; i < CNST; i ++) gra[u][i] = gra[gra[u][i - 1]][i - 1];
        for(int i = E1.head[u]; i; i = E1.last[i])
        {
            int v = E1.to[i];
            if(v == fa) return;
            dfs(v, u); size[u] += size[v];
            ST[++ T][0] = dep[u];
        }
    }

    int LCA(int x, int y)
    {
        if(dep[x] < dep[y]) swap(x, y);
        for(int i = CNST - 1; ~i; i --)
            if(dep[gra[x][i]] >= dep[y]) x = gra[x][i];
        for(int i = CNST - 1; ~i; i --)
            if(gra[x][i] != gra[y][i]) x = gra[x][i], y = gra[y][i];
        return (x == y) ? x : gra[x][0];
    }

    int Get_Dis(int x, int y)
    {
        int ret = dep[x] + dep[y];
        if(!x) return dep[y]; else if(!y) return dep[x];
        x = pos[x], y = pos[y];
        if(x > y) swap(x, y);
        int k = Log[y - x + 1];
        ret = ret - 2 * min(ST[x][k], ST[y - bit[k] + 1][k]);
        return ret;
    }

    int Get_Gra(int x, int y)
    {
        for(int i = CNST - 1; ~i; i --)
            if(dep[gra[x][i]] > dep[y]) x = gra[x][i];
        return x;
    }

    int Work(int u, int v, int k)
    {
        bool flag = 0;
        int x = u;
        for(int i = CNST - 1; i >= 0; i --)
        {
            int tem = gra[x][i]; if(dep[tem] < dep[k]) continue;
            int d1 = Get_Dis(u, tem), d2 = Get_Dis(v, tem);
            if(d1 < d2) x = gra[x][i];
            else if(d1 == d2 && u < v) x = gra[x][i];
        }
         return x;
    }

    void DP(int u, int fa)
    {
        hson[u] = 0; sum[u] = 0;
        for(int i = E2.head[u]; i; i = E2.last[i])
        {
            int v = E2.to[i]; if(!v) continue;
            if(v == fa) continue;
            DP(v, u);
            int t = hson[v];
            int dis = Get_Dis(u, t), dis2 = Get_Dis(u, hson[u]);
            if(dis < dis2) hson[u] = t;
            else if(dis == dis2 && t < hson[u]) hson[u] = t;
            if(!hson[u]) hson[u] = t;
        }
        if(mark[u]) hson[u] = u;
    }

    void DP2(int u, int fa)
    {
        int tot = 0;
        if(hson[fa])
        {
            int t = hson[fa];
            int dis = Get_Dis(u, t), dis2 = Get_Dis(u, hson[u]);
            if(dis < dis2) hson[u] = t;
            else if(dis == dis2 && t < hson[u]) hson[u] = t;
            if(!hson[u]) hson[u] = t;
        }
        for(int i = E2.head[u]; i; i = E2.last[i])
        {
            int v = E2.to[i];
            if(v == fa) continue; DP2(v, u);
            int y = Get_Gra(v, u);
            int x = Work(hson[v], hson[u], u);
            int tem = size[x] - size[v];
            ans[hson[v]] += tem, ans[hson[u]] += size[y] - size[x];
            tot += size[y];
        }
        ans[hson[u]] += size[u] - tot;
        E2.head[u] = 0;
    }

    void Solve()
    {
        int K = read();
        for(int i = 1; i <= K; i ++) b[i] = a[i] = read(), mark[a[i]] = 1;
        sort(a + 1, a + 1 + K, cmp); S[top = 1] = 1; E2.cnp = 1; ans[0] = 0;
        for(int i = 1; i <= K; i ++)
        {
            int lca = LCA(S[top], a[i]);
            while(2333)
            {
                if(dep[S[top - 1]] <= dep[lca])
                {
                    E2.add(lca, S[top --]);
                    if(lca != S[top]) S[++ top] = lca;
                    break;
                }
                else E2.add(S[top], S[top - 1]), top --;
            }
            S[++ top] = a[i];
        }
        while(top > 1) E2.add(S[top], S[top - 1]), top --;
        sum[1] = 0; DP(1, 0); DP2(1, 0);
        for(int i = 1; i <= K; i ++) printf("%d ", ans[b[i]]), mark[b[i]] = 0, ans[b[i]] = 0;
        puts("");
    }

    void init()
    {
        bit[0] = 1; for(int i = 1; i <= 20; i ++) bit[i] = bit[i - 1] << 1;
        Log[0] = -1; for(int i = 1; i < maxn * 2; i ++) Log[i] = Log[i >> 1] + 1;
    }

    int main()
    {
        init(); n = read();
        for(int i = 1; i < n; i ++)
        {
            int x = read(), y = read();
            E1.add(x, y);
        }
        dfs(1, 0);
        for(int i = 1; i <= Log[T]; i ++)
            for(int j = 1; j + bit[i - 1] <= T; j ++)
                ST[j][i] = min(ST[j][i - 1], ST[j + bit[i - 1]][i - 1]);
        int q = read();
        for(int i = 1; i <= q; i ++) Solve();
        return 0;
    }
  • 相关阅读:
    iOS开发——Xcode快捷键
    iOS开发——国际化支持Localizable.strings
    SQL 函数
    常用窗体表单布局
    Extjs grid combo
    怎么完全卸载sql2005?
    ExtJS文件上传
    ExtJS视频学习笔记
    ExtJS问题集——Menu的show()和showBy()函数是什么意思
    C# DataGridView操作
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9420478.html
Copyright © 2020-2023  润新知