P1653 猴子

Posted garen-wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1653 猴子相关的知识,希望对你有一定的参考价值。

猴子!好可爱!不过好难!


问题

给你许多只猴子,每一个时间段他们放手,问猴子掉落的时间。

分析

注意:这里的猴子抓猴子,不一定要手拉手,拽别人尾巴照样不会掉下去!

所以其实是一个无向图的连通问题。

每一个联通分支,答案一定是相同的。

所以可以考虑并查集来维护。而这里是一个带权的并查集。

放手是摧毁连通,想想都是几乎不可能做到的事情。

所以正难则反,我们考虑离线回答问题,从$m-1$到$0$时间段倒着算答案。

那么就是一个添加连通的问题了,直接并查集merge即可。

我们维护ans数组,表示猴子掉下去的时间。

1号猴子吊在树上,怎么都不会掉,所以$ans[1] = INF$

首先当然要连上$m$时间段中,还剩下的边。

然后就可以直接逆序合并集合,回答问题了。

如何维护ans?

这也许是最难的地方了。如果没有学过带权并查集的话,绝对想不出来。我就想不出来

给出代码:

int find(int x)
{
    if(fa[x] == x) return x;
    int temp = find(fa[x]);
    ans[x] = std::min(ans[x], ans[fa[x]]);
    return fa[x] = temp;
}

这个东西什么意思?

一个点的ans,是这个联通分支中最小的ans。

注意一定要先递归,不然从下面弄上去是错的。

先递归的话,先执行的是第二层、第三层,以此类推到叶子。

如果不懂的话就死记吧。。。

其他的东西都是细节,说不了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

const int maxn = 200005, maxm = 400005, INF = 0x3f3f3f3f;
int n, m;
struct Node//the situation of loosing hand
{
    int u, hand;
} s[maxm];
int G[maxn][2];
bool b[maxn][2];
int ans[maxn];
int fa[maxn];
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘)
    {
        if(ch == ‘-‘) s = -1;
        ch = getchar();
    }
    while(ch >= ‘0‘ && ch <= ‘9‘)
    {
        ans = ans * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return s * ans;
}
int find(int x)
{
    if(fa[x] == x) return x;
    int temp = find(fa[x]);
    ans[x] = std::min(ans[x], ans[fa[x]]);
    return fa[x] = temp;
}
void merge(int x, int y, int k)
{
    x = find(x), y = find(y);
    if(x != y)
    {
        if(x == 1) fa[y] = x, ans[y] = k;
        else fa[x] = y, ans[x] = k;
    }
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i++)
    {
        fa[i] = i;
        G[i][0] = read(), G[i][1] = read();
    }
    for(int i = 0; i < m; i++)
    {
        s[i].u = read(), s[i].hand = read() - 1;
        b[s[i].u][s[i].hand] = true;
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= 1; j++)
        {
            if(!b[i][j] && G[i][j] != -1) merge(i, G[i][j], m);
        }
    }
    memset(ans, 0x3f, sizeof(ans));
    for(int i = m - 1; i >= 0; i--)
    {
        if(G[s[i].u][s[i].hand] != -1) merge(s[i].u, G[s[i].u][s[i].hand], i);
    }
    for(int i = 1; i <= n; i++)
    {
        find(i);
        if(ans[i] == INF) printf("-1
");
        else printf("%d
", ans[i]);
    }
    return 0;
}

以上是关于P1653 猴子的主要内容,如果未能解决你的问题,请参考以下文章

《我不是药神》票房超25亿 曝片段呈现群像式演技

华为OD机试 - 猴子爬山(Java) | 机试题+算法思路+考点+代码解析 2023

猴子补丁的应用,猴子补丁来改变日志。

Python 3:猴子补丁代码不能通过多处理重新导入

python笔记69 - 什么是猴子补丁(Monkey Patch)?

Ruby 中的“猴子补丁”到底是啥意思?