首页 > 代码库 > AC日记——猴子 cogs 2043

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 200005using 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\n");        else printf("%d\n",Time[i]);    }    fclose(stdin);    fclose(stdout);    return 0;}

 

AC日记——猴子 cogs 2043