Cogs 1070. [焦作一中2012] 玻璃球游戏 带权并查集,逆序处理

题目: 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

2 3 1 

1 1 

1 2 

2 1 

1 2 

1 1 

2 2 

1 2

CIKLUS 

CIKLUS 

2

【输入输出样例2】

marbles.in

marbles.out

0 3 5 3 4 

1 1 

1 2 

2 4 

1 2 

2 3 

1 2

CIKLUS 

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 }
View Code
原文地址:https://www.cnblogs.com/Var123/p/5275671.html