很神奇的转换

有N只猴子,第一只尾巴挂在树上,剩下的N-1只,要么被其他的猴子抓住,要么抓住了其他的猴子,要么两者均有。

当然一只猴子最多抓两只另外的猴子。

现在给出这N只猴子抓与被抓的信息,

并且在某个时刻可能某只猴子会放掉它其中一只手的猴子,导致某些猴子落地。

求每只猴子落地的时间。

luogu大佬原话:

事实上我们可以把猴子放手的时间当作这条边的边权,而不放手的边权为一个大数,

我们需要求得其实就是一条单源路径,让这条路径最小边权最大,直接输出这个值即可,

若这个值为那个大数,就输出-1。

一条路径最小边权就是断开时间

这个最大的 最小边权,就是到这个点的所有路径都断开的时间

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
int n,m;
const int N=200003,M=N<<2;
int ls[N],rs[N],tm[N][2];

int tot,head[N];
int ev[M],ew[M],enx[M];
void add(int u,int v,int w)
{    ev[++tot]=v,ew[tot]=w,enx[tot]=head[u],head[u]=tot;
    ev[++tot]=u,ew[tot]=w,enx[tot]=head[v],head[v]=tot; }

int dis[N];
struct node
{
    int v,dis;
    bool operator < (const node & o) const
    { return dis<o.dis; }
};
priority_queue <node> q;
void dijk()
{
    dis[1]=m;
    q.push((node){1,m});

    while(!q.empty() )
    {
        node nw=q.top() ;q.pop() ;
        if(dis[nw.v ]!=nw.dis ) continue;

        for(int i=head[nw.v ];i;i=enx[i])
        {
            int val=min(nw.dis ,ew[i]);
            if(dis[ev[i]] < val )
            {
                dis[ev[i]]=val;
                q.push((node){ev[i],val});
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&ls[i],&rs[i]),
        tm[i][0]=tm[i][1]=m;
    for(int i=0;i<m;i++)
    {
        int x,fx;
        scanf("%d%d",&x,&fx);
        tm[x][fx-1]=i;//输入0 - m-1s放手情况 
    }
    for(int i=1;i<=n;i++)
    {
        if(ls[i]!=-1)
            add(i,ls[i],tm[i][0] );
        if(rs[i]!=-1)
            add(i,rs[i],tm[i][1]);
    }
    //求0-m-1s掉落的猴子
    dijk();
    for(int i=1;i<=n;i++)
        if(dis[i]<m) printf("%d\n",dis[i]);
        else printf("-1\n");

    return 0;
}
View Code
01-06 00:51