1452G Game On Tree(拓扑+贪心)

1452G Game On Tree(拓扑+贪心)

Educational Codeforces Round 98 (Rated for Div. 2)

G. Game On Tree

题面Game On Tree

题意:Alice 和 Bob 在一颗有 n n n 个节点的树上进行博弈,一开始 Bob 在树上有 k k k 个士兵,分别在 a i a_i ai 节点上(不重复),而 Alice 在这颗树上只有一个士兵,他需要躲避 Bob 士兵的追捕,当 Alice 的士兵被 Bob 的士兵抓到,即位于同一节点时游戏结束。

每个回合中,Alice 先选择让自己的士兵往邻点移动一步,或者停在原地,然后 Bob 分别对自己的每个士兵选择往邻点移动一步,或者停在原地。

Alice 想要自己的士兵尽可能晚得被抓到,Bob 想要尽可能早得抓到 Alice 的士兵,两人都足够聪明。问当 Alice 将自己的士兵放置于点 1 , 2 , 3... , n 1,2,3...,n 1,2,3...,n 时被抓住的最晚时间是多少。

范围 2 ≤ n ≤ 2 ∗ 1 0 5 ,   1 ≤ k ≤ n − 1 ,   1 ≤ a i ≤ n 2 \le n \le 2*10^5,~1 \le k \le n - 1,~1 \le a_i \le n 2n2105, 1kn1, 1ain

分析:首先如果要判断一个点从逃往哪个点可以延长自己被抓到的时间,就先需要求出每个点 u u u 距离自己最近的 Bob 士兵的距离 d i s t [ u ] dist[u] dist[u],这个可以通过拓扑排序进行预处理出来。

每个点 u u u 都想要前往 d i s t [ v ] > d i s t [ u ] dist[v] > dist[u] dist[v]>dist[u] 的邻点 v v v 中,显然对于最大的 d i s t [ u ] dist[u] dist[u] 是没有办法变得更大,因此我们可以按照 d i s t dist dist 从大到小进行处理,从该点 u u u 出发找到所有可以到达 u u u 的所有点 v v v(需要保证中途不被抓到),去更新这些点的答案。

另外在上述处理过程中可能出现的问题是某些点会被重复遍历很多次,我们利用一个数组 h h h h [ u ] h[u] h[u] 表示当前利用点 u u u 来更新答案时距离最近 Bob 士兵的距离,根据贪心的思想,在处理点 u u u 时只有当眼下距离最近 Bob 士兵的距离 d > h [ u ] d > h[u] d>h[u] 时,才有可能通过点 u u u 得到更优解。

Code

#include <bits/stdc++.h>
using namespace std;
 
inline int read()
{
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}
 
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
 
int n, k;
 
int dist[MAXN], ans[MAXN], h[MAXN];

vector<int> E[MAXN], P[MAXN];

queue<int> que;

signed main()
{
    memset(dist, -1, sizeof(dist));
    n = read();
    for (int i = 0; i < n - 1; i++)
    {
        int u, v;
        u = read(), v = read();
        E[u].push_back(v);
        E[v].push_back(u);
    }
    k = read();
    for (int i = 0; i < k; i++)
    {
        int x = read();
        dist[x] = 0;
        que.push(x);
    }   
    int maxDist = 0;
    while (!que.empty())
    {
        int u = que.front();
        que.pop();
        for (auto v : E[u])
        {
            if (dist[v] >= 0) continue;
            dist[v] = dist[u] + 1;
            que.push(v);
        }
        P[dist[u]].push_back(u);
        maxDist = max(maxDist, dist[u]);
    }
    queue<pair<int, int>> que_pair;
    for (int i = maxDist; i > 0; i--)
    {
        for (auto u : P[i])
        {
            if (h[u] < dist[u])
            {
                if (!ans[u]) ans[u] = i;
                h[u] = dist[u];
                que_pair.push({dist[u], u});
            }
        }
        while (!que_pair.empty())
        {
            int d = que_pair.front().first;
            int u = que_pair.front().second;
            que_pair.pop();
            if (--d == 0) continue;
            for (auto v : E[u])
            {
                int temp = min(d, dist[v]);
                if (h[v] < temp)
                {
                    if (!ans[v]) ans[v] = i;
                    h[v] = temp;
                    que_pair.push({temp, v});
                }
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (i > 1) cout << " ";
        cout << ans[i];
    }
    cout << endl;
    return 0;
}

【END】感谢观看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值