zoukankan      html  css  js  c++  java
  • [SDOI2018]战略游戏 圆方树,树链剖分

    [SDOI2018]战略游戏

    这题是道路相遇题解)的升级版,询问的两个点变成了(S)个点。

    LG传送门

    还是先建出圆方树,考虑对于询问的(S)个点,答案就是圆方树上能包含这些点的最小连通块中的圆点个数减去(S)。问题变成了怎样求这样的连通块中的圆点个数,直接给结论吧:先搞出树的dfs序,把询问的点按dfs序从小到大排一遍序,每次把答案加上第(i)和第(i + 1)个点之间的圆点个数,但是不算lca,再加上第(1)个和第(S)个点之间的圆点个数,然后除以二就得到了这个连通块内不包括整个连通块的lca的圆点个数,可以证明这个连通块内除了lca的所有点都被算了两次,最后判断一下lca是不是圆点,减去(S)就是答案。

    实测树剖比倍增快很多。

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define R register
    #define I inline
    #define B 10000000
    using namespace std;
    const int N = 400003;
    char buf[B], *p1, *p2;
    I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
    I int rd() {
        R int f = 0; R char c = gc();
        while (c < 48 || c > 57)
            c = gc();
        while (c > 47 && c < 58)
            f = f * 10 + (c ^ 48), c = gc();
        return f;
    }
    int h[N], H[N], sta[N], dfn[N], low[N], vis[N], fa[N], dep[N], siz[N], son[N], top[N], dis[N], q[N], n, c, tim, cnt, stp;
    struct edge { int s, g; }e[N], E[N];
    I void add(int x, int y) { e[++c] = (edge){h[x], y}, h[x] = c; }
    I void Add(int x, int y) { E[++c] = (edge){H[x], y}, H[x] = c; }
    I int min(int x, int y) { return x < y ? x : y; }
    I int cmp(int x, int y) { return dfn[x] < dfn[y]; }
    void dfs(int x) {
        vis[sta[++stp] = x] = 1, dfn[x] = low[x] = ++tim;
        for (R int i = h[x], y, z; i; i = e[i].s)
            if (!dfn[y = e[i].g]) {
                dfs(y), low[x] = min(low[x], low[y]);
                if (low[y] >= dfn[x]) {
                    Add(++cnt, x), Add(x, cnt);
                    do {
                        vis[z = sta[stp--]] = 0, Add(cnt, z), Add(z, cnt);
                    } while (z ^ y);
                }
            }
            else
                low[x] = min(low[x], dfn[y]);
    }
    void dfs1(int x, int f) {
        fa[x] = f, dep[x] = dep[f] + 1, siz[x] = 1, dis[x] = dis[f] + (x <= n);
        for (R int i = H[x], y, m = 0; i; i = E[i].s)
            if ((y = E[i].g) ^ f) {
                dfs1(y, x), siz[x] += siz[y];
                if (siz[y] > m)
                    m = siz[x], son[x] = y;
            }
    }
    void dfs2(int x, int r) {
        dfn[x] = ++tim, top[x] = r;
        if (son[x])
            dfs2(son[x], r);
        for (R int i = H[x], y; i; i = E[i].s)
            if ((y = E[i].g) ^ fa[x] && y ^ son[x])
                dfs2(y, y);
    }
    I int lca(int x, int y) {
        while (top[x] ^ top[y])
            dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]];
        return dep[x] < dep[y] ? x : y;
    }
    I int query(int x, int y) { return dis[x] + dis[y] - (dis[lca(x, y)] << 1); }
    int main() {
        R int T = rd(), m, Q, S, i, x, y, ans;
        while (T--) {
            memset(h, 0, sizeof h), memset(H, 0, sizeof H), memset(son, 0, sizeof son), memset(dfn, 0, sizeof dfn);
            cnt = n = rd(), m = rd(), c = 0;
            for (i = 1; i <= m; ++i)
                x = rd(), y = rd(), add(x, y), add(y, x);
            c = tim = stp = 0, dfs(1), tim = 0, dfs1(1, 0), dfs2(1, 1), Q = rd();
            while (Q--) {
                S = rd();
                for (i = 1; i <= S; ++i)
                    q[i] = rd();
                sort(q + 1, q + S + 1, cmp), ans = query(q[1], q[S]);
                for (i = 2; i <= S; ++i)
                    ans += query(q[i - 1], q[i]);
                printf("%d
    ", (ans >> 1) - S + (lca(q[1], q[S]) <= n));
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    【机器学习实战】第12章 使用FP-growth算法来高效发现频繁项集
    【机器学习实战】第11章 使用 Apriori 算法进行关联分析
    【机器学习实战】第 10 章 K-Means(K-均值)聚类算法
    【机器学习实战】第9章 树回归
    【机器学习实战】第8章 预测数值型数据:回归
    【机器学习实战】第7章 集成方法 ensemble method
    【机器学习实战】第6章 支持向量机
    学习计划
    第二次作业
    第一次作业
  • 原文地址:https://www.cnblogs.com/cj-chd/p/10294681.html
Copyright © 2011-2022 走看看