AC日记——猴子 cogs 2043

2043. 猴子

★★   输入文件:monkeya.in   输出文件:monkeya.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

有n只猴子,第一只尾巴挂在树上,剩下的n-1只,要么被其他的猴子抓住,要么抓住了其他的猴子,要么两者均有。当然一只猴子最多抓两只另外的猴子,因为只有两只猴爪子嘛。现在给出这n只猴子抓与被抓的信息,并且在某个时刻可能某只猴子会放掉它左手或右手的猴子,导致某些猴子落在地上。求每只猴子落地的时间。

【输入格式】

第一行两个n,m,表示有n只猴子,并且总时间为m-1.

接下来n行,描述了每只猴子的信息,每行两个数,分别表示这只猴子左手和右手抓的猴子的编号,如果是-1,表示该猴子的那只手没抓其他的猴子。

再接下来M行,按时间顺序给出了一些猴子放手的信息,第1+n+i行表示i-1时刻某只猴子的放手信息,信息以两个数给出,前者表示放手的猴子的编号,后者表示其放的是哪只手,1左2右。

【输出格式】

共输出n行,第i行表示第i只猴子掉落的时刻,若第i只猴子道M-1时刻以后还没掉落,就输出-1。

【样例输入】

3 2

-1 3

3 -1

1 2

1 2

3 1

【样例输出】

-1

1

1

【提示】

n<=200000,m<=400000

【来源】

在此键入。

思路:

  逆向并查集~;

  这个题仔细读读可以发现这群猴子不按套路抓尾巴;

  可能一只猴子的尾巴会被很多只猴子抓;

  所以,这个题就成为了一个判断每个时间点连通性的问题;

  判断图的联通性自然是用并查集呀;

  但是,,,这个题貌似直接搞并查集不可行;

  所以,,要加一点点乱搞的操作;

  逆向并查集;

  我们读入每个猴子的左右手抓的尾巴(建图);

  然后,开始放手(删边);

  放手的同时,把放手的操作记录下来;

  然后,开始从第m-1秒到第0秒把放手的边加回去;

  没加一条边就通过并查集判断一下图的联通性;

  当当前块与1号联通时,就记录time;

  怎么记录time呢?略略恶心,,就不讲了,,可以去看看我的代码(直白如话);

  最后输出;

  轻松ac;

来,上代码:

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

#define maxn 200005

using namespace std;

struct NodeType {
    int l,r;
    
    bool li,ri;
};
struct NodeType node[maxn<<2];

struct EdgeType {
    int to,next;
};
struct EdgeType edge[maxn<<2];

int if_z,n,m,f[maxn],head[maxn],Time[maxn];
int cnt,do_s[maxn<<1],do_w[maxn<<1];

char Cget;

bool if_[maxn],did[maxn];

inline void read_int(int &now)
{
    now=0,if_z=1,Cget=getchar();
    while(Cget>'9'||Cget<'0')
    {
        if(Cget=='-') if_z=-1;
        Cget=getchar();
    }
    while(Cget>='0'&&Cget<='9')
    {
        now=now*10+Cget-'0';
        Cget=getchar();
    }
    now*=if_z;
}

inline void edge_add(int from,int to)
{
    cnt++;
    edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt;
}

int find(int x)
{
    if(x==f[x]) return x;
    f[x]=find(f[x]);
    return f[x];
}

void search(int now)
{
    did[now]=true;
    if(node[now].l!=-1&&node[now].li)
    {
        int x=find(now),y=find(node[now].l);
        if(x>y) swap(x,y);
        if(x!=1)
        {
            edge_add(x,y);
            edge_add(y,x);
        }
        f[y]=x;
        if(!did[node[now].l]) search(node[now].l);
    }
    if(node[now].r!=-1&&node[now].ri)
    {
        int x=find(now),y=find(node[now].r);
        if(x>y) swap(x,y);
        if(x!=1)
        {
            edge_add(x,y);
            edge_add(y,x);
        }
        f[y]=x;
        if(!did[node[now].r]) search(node[now].r);
    }
}

void search_(int now,int time_)
{
    if_[now]=true;
    Time[now]=time_;
    for(int i=head[now];i;i=edge[i].next)
    {
        if(!if_[edge[i].to]) search_(edge[i].to,time_);
    }
}

int main()
{
    freopen("monkeya.in","r",stdin);
    freopen("monkeya.out","w",stdout);
    memset(Time,-1,sizeof(Time));
    read_int(n),read_int(m);
    m--;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        read_int(node[i].l);
        read_int(node[i].r);
        if(node[i].l!=-1) node[i].li=true;
        if(node[i].r!=-1) node[i].ri=true;
    }
    for(int i=0;i<=m;i++)
    {
        read_int(do_s[i]),read_int(do_w[i]);
        if(do_w[i]==1) node[do_s[i]].li=false;
        else node[do_s[i]].ri=false;
    }
    for(int i=1;i<=n;i++)
    {
        if(!did[i]) search(i);
    }
    for(int i=m;i>=0;i--)
    {
        int x=do_s[i],y,x_,y_;
        if(do_w[i]==1) y=node[do_s[i]].l;
        else y=node[do_s[i]].r;
        if(y==-1) continue;
        x_=find(x),y_=find(y);
        if(x_>y_) swap(x_,y_);
        if(x_!=1&&y_!=1)
        {
            edge_add(x_,y_);
            edge_add(y_,x_);
        }
        else if(x_!=1&&y_==1) Time[x_]=i;
        else if(x_==1&&y_!=1) Time[y_]=i;
        f[y_]=x_;
    }
    for(int i=1;i<=n;i++)
    {
        if(Time[i]>=0) search_(i,Time[i]);
    }
    for(int i=1;i<=n;i++)
    {
        if(Time[i]<0) printf("-1
");
        else printf("%d
",Time[i]);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6412685.html