八中教室的灯加强版 【并查集】

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目:

八中教室的灯加强版

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 79  Solved: 38
[Submit][Status][Web Board]

Description

八中一共有被用M条双向道路连接的N个教室(1<=N,M<=3000)。为了关闭整个八中,master wen 计划每一次关
闭掉一个教室。当一个教室被关闭了,所有的连接到这个教室的道路都会被关闭,而且再也不能够被使用。master
 wen现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭教室之前的时间)时他的八中是否是“全
连通的”——也就是说从任意的一个开着的教室开始,能够到达另外的一个教室。注意自从某一个时间之后,可能
整个八中都开始不会是“全连通的”。

Input

第一行给出数字N,M,代表有N个教室,M条边,1<=N,M<=200000
接下来N行来用描述教室之间相连的情况
接下来N行,每行给出一个数字,代表关闭了哪个教室的灯

Output

输出N行,每行输出"YES"或"NO".
第一行输出最开始时整个八中是不是连通的
后面的N-1用来描述关闭某个教室的灯后,八中是不是连通的。

Sample Input

4 3
1 2
2 3
3 4
3
4
1
2

Sample Output

YES
NO
YES
YES

HINT

题目大意:

给你n个点和m条边,每次删掉一个点(被删的点就永久消失),并且与这个点相连的边也被删掉,现求删除这个点后,场上的所有点是否还能连通。

题目解析:

如果要边输入边删点的话,那么肯定要构造一棵树,并且还要找删点后一个还未删的点去进行搜索,看整个图是否连通,如果数据小还好,但如果数据大的话,肯定会超时。
那么我们换一种思路,既然是看整个图是否连通,那么是不是看每一个的根结点是否一致,那么最好的方法就是使用并查集,为了使时间复杂度更小,我们可以使之扁平化(但好像正着搜没有什么作用,因为每次是删头结点,并不是连接两点),但若使用并查集的话,每次搜索还是要搜寻每个点的根节点,并且还要判断每一条边能不能走,这也一定会超时,那如果每次不遍历每一个点,那是否就能不超时呢?
其实要做到这一点也不难,我们不如反向思维,是不是从开头每次删一个点直至删完,就相当于从后面做每次加一个点直至补完,并且从结尾往前加点,那么每次符合条件的边就不可能变动(就不用考虑之前连接的两点是否连通),并且每一个节点的根就只会连到另一个节点上,扁平化就更能体现作用。
但现在还是没有解决遍历点的问题及遍历边的问题(重中之重,打起精神来,注意!)
遍历点的问题:是不是每加一个点,就相当于多了一个连通块,而每把两个根节点不相同的连通块相连就少了一个根节点,若要使整个图为一个环形,则整个图为一个连通块。
遍历边的问题:既然点是按先后顺序出现的,而边的出现是看两头的点是否出现,若按平常的话,一定要去搜索,在这里我们只需排序即可。我们先记录下每一个点出现的先后排名,然后记录下每一条边的两个端点,最后按照每条边的端点出现的先后排序即可(记得按每条边的最晚出现的点与对方做比较)。我们回到程序中,在搜的时候只要看当前的边是否符合条件,若符合,则把条的两端点的根相连,若不符合,则不往下继续搜

code:

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 const int N=200001;
 4 using namespace std;
 5 int n,m,tot;
 6 int ver[N*2],nxt[N*2],head[N],f[N],k[N];
 7 int sum;
 8 bool flag[N];
 9 bool ans[N];
10 void inint(){
11     freopen("light.in","r",stdin);
12     freopen("light.out","w",stdout);
13 }
14 inline int read(){
15     int x=0,f=1;char ch=getchar();
16     while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
17     while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
18     return x*f;
19 }
20 inline void write(int x)
21 {
22     if(x<0)x=-x,putchar(‘-‘);
23     if(x>9)write(x/10);
24     putchar(x%10+‘0‘);
25 }
26 void add(int x,int y){
27     ++tot;
28     ver[tot]=y;
29     nxt[tot]=head[x];
30     head[x]=tot;
31 }
32 int find(int fa){
33     if(f[fa]==fa)return fa;
34     return f[fa]=find(f[fa]);
35 }
36 int main()
37 {
38     //inint();
39     n=read(),m=read();
40     for(int i=1;i<=n;i++){
41         f[i]=i;
42     }
43     for(int i=1,x,y;i<=m;i++){
44         x=read(),y=read();
45         add(x,y);
46         add(y,x);
47     }
48     for(int i=1;i<=n;i++){
49         k[i]=read();
50     }
51     for(int i=n;i>=1;i--){
52         sum++;
53         flag[k[i]]=true;
54         for(int j=head[k[i]];j;j=nxt[j]){
55             int y=ver[j];
56             if(flag[y]&&find(y)!=find(k[i])){
57                 f[find(y)]=f[find(k[i])];
58                 sum--;
59             }
60         }
61         if(sum==1)ans[i]=true;
62     }
63     for(int i=1;i<=n;i++){
64         if(ans[i])printf("YES\n");
65         else printf("NO\n");
66     }
67     return 0;
68 }
69 /*
70 4 3
71 1 2
72 2 3
73 3 4
74 3
75 4
76 1
77 2
78 */

原文地址:https://www.cnblogs.com/nlyzl/p/11776244.html

时间: 2024-10-16 12:25:28

八中教室的灯加强版 【并查集】的相关文章

可持久化并查集加强版 BZOJ 3674

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 3225  Solved: 1192[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可

bzoj3674 可持久化并查集加强版

Description 自从zkysb出了可持久化并查集后--hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:-- n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为00<n,m<=2*10^5 Samp

BZOJ 3674: 可持久化并查集加强版

3674: 可持久化并查集加强版 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 2605  Solved: 977[Submit][Status][Discuss] Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了!ndsf:暴力就可以轻松虐!zky:…… n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状

[BZOJ3674]可持久化并查集加强版&amp;[BZOJ3673]可持久化并查集 by zky

思路: 用主席树维护并查集森林,每次连接时新增结点. 似乎并不需要启发式合并,我随随便便写了一个就跑到了3674第一页?3673是这题的弱化版,本来写个暴力就能过,现在借用加强版的代码(去掉异或),直接吊打暴力程序. 1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch

bzoj3673可持久化并查集 by zky&amp;&amp;bzoj3674可持久化并查集加强版

bzoj3673可持久化并查集 by zky 题意: 维护可以恢复到第k次操作后的并查集. 题解: 用可持久化线段树维护并查集的fa数组和秩(在并查集里的深度),不能路径压缩所以用按秩启发式合并,可以使合并均摊复杂度为O(nlog2n).可持久化线段树实际上就是在更新节点时按主席树的插入方式新建一条路径(其实主席树就是可持久化权值线段树). 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

交通灯 并查集

Problem Description 相信交通灯对于你来说并不陌生,交通灯分为红色和绿色两个阶段,这两个阶段互相更替,保障着道路的安全. 在杭州一共有n个路口,编号依次为1到n.这些路口之间连接着m条双向道路,每条道路连接着两个不同的路口,且任意两个路口之间最多连接着一条道路.每条道路中央都设置着一个交通灯. 为了保障道路的安全,对于任意两条道路,如果它们连接了同一个路口,那么它们不能同色. 你的朋友正乘着飞机从杭州的上空飞过,并拍了一张杭州的照片.在照片里,每条道路的交通灯的颜色都清晰可辨.

【bzoj3674】 可持久化并查集加强版

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接) 题意 维护并查集3个操作:合并:回到完成第k个操作后的状态:查询. Solution 其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]. 细节 终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并每快多少→_→ 代码 // bzoj3674 #include<algorithm> #include<iostream>

【BZOJ 3674】可持久化并查集加强版&amp;【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破之. 3:输出判断即可. 难者不会,会者不难,1h前我还在膜这道题,现在吗hhh就当支持下zky学长出的题了. 3673: #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=ge

poj 2912 并查集(食物链加强版)

题目:给出n个人玩剪刀石头布的游戏,其中有一个人是裁判,剩下的人分为3组,每一组的人只出某一种手型,裁判可以任意出.问是否能判断出哪个人是裁判 链接:点我 分分钟看吐血,先把食物链看懂吧 枚举裁判,然后并查集判断 裁判由于可以任意出,所以可能属于任意一个集合,所以有裁判参与的会合不考虑,然后并查集部分和食物链很相似. 如果某个裁判那里出现了矛盾,则记录一下在哪出问题. 然后判断是否只有一个裁判没有出现问题.如果只有一个,说明可以确定,那么就是剩下的人出问题的最大值.因为只有否定了其它所有人,才能