zoj3811(并查集)

题意:

有一个仓库,有很n个点,m条边,还有k个点有传感器;

现在给出n,m,k然后给出k个监视器的位置,给出m条边;

再输入l,表示总共有k个传感器被触发了(每个传感器只会第一次经过时触发);

和触发的顺序;

问可以可以把整张图走完 , 并且是按照给出的触发顺序;

思路:

我们一开始先把触发器所在的点排除,然后把其它点用并查集并起来;

然后按顺序一个个把触发器的点放进去;

假如我们现在放入第三个触发器;然后他和第二个触发器,并在了一起,说明可以走到(此时其它触发器都还没放进去,那么自然不存在触发顺序的问题)

到最后只要每个触发器放进去后,都可以和前一个并在一起,并且图是联通的,那么就可以;

AC代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 100000 + 10;
vector <int> e[N];
int p[N];
int findp(int x){
    return x == p[x] ? x : p[x] = findp(p[x]);
}
int Union(int x,int y){
    x = findp(x),y = findp(y);
    if(x == y)
		return false;
    p[x]=y;
    return true;
}
int mm[N],a[N],b[N];
int main(){
    int n,m,k,t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 0; i <= n; i++){
            e[i].clear();
            p[i] = i;
            mm[i] = 0;
        }
        for(int i = 1; i <= k; i++){
            scanf("%d",&b[i]);
            mm[b[i]] = 1;
        }
        for(int i = 0; i < m;i++){
			int x,y;
            scanf("%d%d",&x,&y);
            e[x].push_back(y);
            e[y].push_back(x);
        }
        int l,flag=0;
        scanf("%d",&l);
        for(int i=1;i<=l;i++){
            scanf("%d",&a[i]);
            if(!mm[a[i]]){
                flag=1;
            }
        }
        if(l!=k||flag){
            puts("No");
            continue;
        }
        mm[a[1]] = 0;
        for(int i = 1;i <= n; i++){
            if(mm[i])
				continue;
            for(int j = 0; j < e[i].size(); j++){
                int v = e[i][j];
                if(mm[v])
					continue;
                Union(i,v);
            }
        }  

        flag = 0;
        for(int i = 2;i <= k;i++){
            mm[a[i]] = 0;
            for(int j = 0;j < e[a[i]].size(); j++){
                int v = e[a[i]][j];
                if(mm[v])
					continue;
                Union(a[i],v);
            }
            if(findp(a[i])!=findp(a[i-1])){
                flag = 1;
                break;
            }
        }
        if(flag)
			puts("No");
        else {
            memset(mm,0,sizeof(mm));
            for(int i=1;i<=n;i++){
                mm[findp(i)]++;
            }
            flag = 0;
            for(int i = 1; i <= n; i++){
                if(mm[i]==n)flag=1;
            }
            if(!flag)
			   	puts("No");
            else
			   	puts("Yes");
        }
    }
    return 0;
}  
时间: 2024-09-28 21:56:51

zoj3811(并查集)的相关文章

ZOJ 3811 Untrusted Patrol【并查集】

题目大意:给一个无向图,有些点有装监视器记录第一次到达该点的位置,问是否存在一条路径使得监视器以给定的顺序响起,并且经过所有点 思路:牡丹江网络赛的题,当时想了种并查集的做法,通神写完程序WA了几发,此时JYB用BFS秒了,索性最后还是调出来了,今天自己写了下,感觉唯一的坑点就是需要遍历完所有的点 //zoj3811 #include <stdio.h> #include <string.h> #include <algorithm> #include <queu

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a

并查集(个人模版)

并查集: 1 int find(int a) 2 { 3 int r=a; 4 while(f[r]!=r) 5 r=f[r]; 6 int i=a; 7 int j; 8 while(i!=r) 9 { 10 j=f[i]; 11 f[i]=r; 12 i=j; 13 } 14 return r; 15 } 16 int merge(int a,int b) 17 { 18 int A,B; 19 A=find(a); 20 B=find(b); 21 if(A!=B) 22 { 23 f[B

并查集应用

题目描述: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls

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

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

BZOJ1015[JSOI2008]星球大战starwar[并查集]

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5253  Solved: 2395[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重

HDU 5606 tree 并查集

tree 把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小. 开一个并查集,每次读到边权是0的边就合并.最后Ans?i??=size[findset(i)],size表示每个并查集根的size Ans_i=size[findset(i)],sizeAns?i??=size[findset(i)],size表示每个并查集根的sizesize. #include<cstdio> #include<cstring> #include<algorithm>

HDU 5441 离线处理 + 并查集

题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用并查集.离线处理,把边按权值排序,把问题按大小排序.然后离线的过程就是不断向图中加边的过程. 比如样例如下: 然后离线处理,排完序后将会是一条一条的加边:问题也排了序,因此是个累加过程... 1 #include <cstdio> 2 #include <iostream> 3 #in

poj1988 Cube Stacking(并查集

题目地址:http://poj.org/problem?id=1988 题意:共n个数,p个操作.输入p.有两个操作M和C.M x y表示把x所在的栈放到y所在的栈上(比如M 2 6:[2 4]放到[1 6]上为[2 4 1 6]),C x为输出x下面有几个数. 思路:并查集每个集合以栈最下面的数为根,维护两个数组num[x]表示x所在集合节点总数,count[x]表示x下方节点个数.每次查找压缩路径的时候更新count(换父节点的时候每轮都把父节点的count加给儿子,就可以一直更新到x所在栈