• 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;
    }
  • 相关阅读:
    通过AI识图判断图片是否为小票
    orcl 定时器
    防止表单重复提交常规方法
    代码规范案例(ssh分页)
    jquery的ajax提交时“加载中”提示的处理方法
    利用JS弹出层实现简单的动态提示“正在加载中,请稍等...”
    jquery 排序table的列
    Java多线程与网络编程综合使用
    大型Oracle数据库设计方案(精华)
    20155307 2016-2017-2 《Java程序设计》第10周学习总结
  • 原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6412685.html
Copyright © 2020-2023  润新知