zoukankan      html  css  js  c++  java
  • 常州模拟赛d2t3 小X的佛光

    平日里最喜欢做的事就是蒸发学水。
    【题目描述】
    小 X 所在的城市 X 城是一个含有 N 个节点的无向图,同时,由于 X 国是一
    个发展中国家,为了节约城市建设的经费,X 国首相在建造 X 城时只建造 N – 1
    条边,使得城市的各个地点能够相互到达。
    小 X 计划蒸发 Q 天的学水,每一天会有一名学水从 A 地走到 B 地,并在沿
    途各个地点留下一个水塘。此后,小 X 会从 C 地走到 B 地,并用佛光蒸发沿途
    的水塘。由于 X 城是一个学佛横行的城市,学水留下的水塘即使没有被小 X 蒸
    发,也会在第二天之前被其他学佛蒸发殆尽。
    现在,小 X 想要知道,他每一天能够蒸发多少水塘呢?
    【输入格式】
    从文件 light.in 中读取数据。
    第一行三个整数 N、Q、NUM,分别表示 X 城地点的个数,小 X 蒸发学水的
    天数,以及测试点编号。注意,测试点编号是为了让选手们更方便的获得部分分,
    你可能不需要用到这则信息,在下发的样例中,测试点编号的含义是该样例满足
    某一测试点限制。
    N – 1 行,每行两个整数 X、Y,表示 X 地与 Y 地之间有一条边。
    接下来 Q 行,每行三个整数 A、B、C,表示一天中,有一名学水从 A 地走到
    B 地,而小 X 会从 C 地走到 B 地。
    【输出格式】
    输出 Q 行,每行一个整数,表示小 X 能够蒸发的水塘数。
    【样例 1 输入】
    3 3 1
    1 2
    2 3
    1 2 3

    1 1 3

    3 1 3

    【样例 1 输出】
    1

    1

    3

    分析:这道题的本质就是要求树上同一个点为起点到两个端点的路径交,暴力的复杂度是O(nq)的,可以过50%的点,因为涉及到路径,如果用树链剖分可以过16个点,不过不能用memset,要用时间戳。正解非常巧妙,其实对于树上的任意三点只有可能是两种情况:一条链或者以某个点为中心.

    显然对于第二种情况,我们只需要求出中心到B点的距离就好了,如果是一条链我们该怎么做呢?这个时候我们可以把中心定义为深度为中位数的那个点,结合两个中心的定义,我们可以脑补出怎么求中心:ABC三个点两两求LCA,其中深度最大的LCA就是中心,最后求一下中心到B点的距离就好了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int maxn = 200010;
    
    int n, q, num,head[maxn],to[maxn * 2],nextt[maxn * 2],tot = 1,dist[maxn],fa[maxn][20];
    
    void add(int x, int y)
    {
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void dfs(int u, int from, int d)
    {
        dist[u] = d;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (v != from)
            {
                fa[v][0] = u;
                dfs(v, u, d + 1);
            }
        }
    }
    
    int lca(int x, int y)
    {
        if (x == y)
            return x;
        if (dist[x] < dist[y])
            swap(x, y);
        for (int i = 19;i >= 0; i--)
            if (dist[fa[x][i]] >= dist[y])
                x = fa[x][i];
        if (x == y)
            return x;
        for (int i = 19; i >= 0; i--)
            if (fa[x][i] != fa[y][i])
            {
                x = fa[x][i];
                y = fa[y][i];
            }
        return fa[x][0];
    }
    
    int main()
    {
        scanf("%d%d%d", &n, &q, &num);
        for (int i = 1; i < n; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
            add(y, x);
        }
        dfs(1, 0, 1);
        for (int j = 1; j <= 19; j++)
            for (int i = 1; i <= n;i++)
                fa[i][j] = fa[fa[i][j - 1]][j - 1];
        while (q--)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            int d = lca(a, b), e = lca(b, c), f = lca(a, c);
            if (dist[d] < dist[e])
                swap(d, e);
            if (dist[d] < dist[f])
                swap(d, f);
            printf("%d
    ", dist[d] + dist[b] - 2 * dist[lca(d, b)] + 1);
        }
    
        return 0;
    }

     

  • 相关阅读:
    Codeforces 845E Fire in the City 线段树
    Codeforces 542D Superhero's Job dp (看题解)
    Codeforces 797F Mice and Holes dp
    Codeforces 408D Parcels dp (看题解)
    Codeforces 464D World of Darkraft
    Codeforces 215E Periodical Numbers 容斥原理
    Codeforces 285E Positions in Permutations dp + 容斥原理
    Codeforces 875E Delivery Club dp
    Codeforces 888F Connecting Vertices 区间dp (看题解)
    Codeforces 946F Fibonacci String Subsequences dp (看题解)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7417942.html
Copyright © 2011-2022 走看看