题目: http://cojs.tk/cogs/problem/problem.php?pid=1070
1070. [焦作一中2012] 玻璃球游戏
★ 输入文件:marbles.in
输出文件:marbles.out
简单对比
时间限制:1 s 内存限制:128 MB
【问题描述】
小x的业余生活中,有一项是玩滚玻璃球游戏。
某天,小x想到了一种很无趣的玩法,当然,这种玩法就是为了玩看题的你们。
小x首先建立了一个单向轨道,这个单向轨道可以抽象成一个有向图,每个顶点的出度都是1,也就是由每个点出发,只有一条边连向其他的点。
小x的游戏最初规则是这样的:让玻璃球从某一个点出发,沿着有向边的方向,移动到它的下一个顶点,如果还能移动,就继续移动,直到没有相邻的边,当然会存在在一个环里不停运动的情况。
为了增加难度,小x决定将游戏规则增强,他会提出一系列问题,让你回答:
1) 格式:1 X.查询玻璃球由编号为X的点出发,最终在哪个点停下来,如果能停下来,输出最后的点的编号,如果停不下来,输出”CIKLUS”.
2) 格式:2 X.删除由X出发的那条有向边。
【输入】
第一行包含一个正整数N(1<=N<=300000),表示图的顶点数。
第二行包含由空格隔开N个正整数,第i个数表示从i顶点可以通过出边到达的定点编号,0表示该点没有出边。
接下来的一行包含1个整数Q(1<=Q<=300000),表示询问的次数。
再接下来Q行,每行表示一次查询,格式如题目描述。
【输出】
对于第1类询问,输出玻璃球停止时所在顶点编号,每行1个,按照查询的顺序输出。如果玻璃球无法停止,输出”CIKLUS”即可.
【输入输出样例1】
marbles.in |
marbles.out |
3 2 3 1 7 1 1 1 2 2 1 1 2 1 1 2 2 1 2 |
CIKLUS CIKLUS 1 1 2 |
【输入输出样例2】
marbles.in |
marbles.out |
5 0 3 5 3 4 6 1 1 1 2 2 4 1 2 2 3 1 2 |
1 CIKLUS 4 3 |
【数据范围】
40% 数据保证 N<=100, Q<=1000
题解:
摘自liu_runda:
先处理完所有删边操作,再逆序处理所有操作(原来的删边处理时改为添边)。
维护一个带权并查集(所谓的权就是会不会走到环路)。
最后一个点用递归find()会爆栈,改迭代find()就可以了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 300010 4 #define MAXQ 300010 5 int end[MAXN],fh[MAXQ],x[MAXQ],ans[MAXQ],father[MAXN]; 6 bool del[MAXN],circle[MAXN]; 7 int read() 8 { 9 int s=0,fh=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 12 return s*fh; 13 } 14 inline int Findfather(int o) 15 { 16 if(o==father[o])return father[o]; 17 else 18 { 19 father[o]=Findfather(father[o]); 20 circle[o]=circle[father[o]]; 21 return father[o]; 22 } 23 } 24 inline void ak(int aa,int bb) 25 { 26 int a1=Findfather(aa); 27 int b1=Findfather(bb); 28 if(a1!=b1)father[a1]=b1; 29 else 30 { 31 circle[a1]=true;circle[b1]=true; 32 } 33 } 34 int main() 35 { 36 freopen("marbles.in","r",stdin); 37 freopen("marbles.out","w",stdout); 38 int i,N,Q,lans,xx; 39 N=read(); 40 for(i=1;i<=N;i++)end[i]=read(),father[i]=i; 41 Q=read(); 42 for(i=1;i<=Q;i++) 43 { 44 fh[i]=read();x[i]=read(); 45 } 46 memset(del,false,sizeof(del)); 47 for(i=1;i<=Q;i++) 48 { 49 if(fh[i]==2)del[x[i]]=true; 50 } 51 memset(circle,false,sizeof(circle)); 52 for(i=1;i<=N;i++) 53 { 54 if(del[i]==false&&end[i]!=0)ak(i,end[i]); 55 } 56 lans=0; 57 for(i=Q;i>=1;i--) 58 { 59 if(fh[i]==1) 60 { 61 xx=Findfather(x[i]); 62 if(circle[x[i]]==true)ans[++lans]=-1; 63 else ans[++lans]=Findfather(x[i]); 64 } 65 else 66 { 67 ak(x[i],end[x[i]]); 68 } 69 } 70 for(i=lans;i>=1;i--) 71 { 72 if(ans[i]!=-1)printf("%d ",ans[i]); 73 else printf("CIKLUS "); 74 } 75 fclose(stdin); 76 fclose(stdout); 77 return 0; 78 }