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; }