并查集初步题目(2)

  • vector和邻接表
  • 并查集的一个很风骚的技巧

一. vector数组操作

包含vector头文件

声明:vector<type> name;

方法:

  1. 加入一个元素至最后:vec.push_back(val);
  2. 清空数组中的所有元素:vec.clear();
  3. 访问其中元素:vec.at(i);
  4. vector中元素的个数:vec.size();
  5. 指定当前vector内元素个数:vec.resize(n); 会保留前n个元素。

邻接表是一种储存图的方式,通常使用链表或者vector可变长数组实现。由表头节点和表节点组成,图中的每一个顶点都在邻接表中为一个表头节点。

邻接表与普通数组储存图的好处在于节约了空间与时间。

如果要遍历一个N个节点的图,数组需要两层for每层N次,事实上一个点并不一定与其它所有点都相邻,进行了无用的判断,还耗费了空间。

如果使用邻接表,使用vector类,可以使速度加快,空间变小,邻接表只储存于表头节点相邻的顶点,因此少了不必要的空间和遍历。

题目:

Hungar个人很喜欢曹操这个人,所以这次有机会穿越到三国时代,他想帮助曹操打赢赤壁之战。 
但是他去晚了,当他穿越到那的时候发现大火已经在蔓延了,所以他能做的就是马上告诉曹操把已经着火的船的锁链(船与船相连都是靠锁链达到的)给破坏掉使火不会蔓延到附近的船只。

现在告诉你曹操一共有N艘船,M条铁链,船只编号从0开始到n-1。 
然后再告诉你依次着火的船只编号,问舍弃那艘船以后,剩下的船只能形成几个连通块(只要是被铁链连在一起的全部船只,就算一共连通块)。 
船与船之间可能存在多条锁链。

Input

输入包括第一行两个整数,N(1 <= N <= 2M)和M(1 <= M <= 200,000)。 
接下来M行,每行包括两个整数x和y(x != y),分别表示编号为x和y的船只被一根锁链连起来。 
再接下来一个正整数T表示着火船只的数量。 
接下来T行,每行包含一个整数z表示被烧船只的编号,编号不会出现一样的,也就是说已经被烧的船只不会再去烧它。

Output

输出z+1个数,第一行为着火前这些船的连通块数,后z行表示每次依次烧掉一只船后,剩下的连通块数。

Sample Input

8 13
0 1
1 6
6 5
5 0
0 6
1 2
2 3
3 4
4 5
7 1
7 2
7 6
3 6
5
1
6
3
5
7

Sample Output

1
1
1
2
3
3

由于题目中顶点的数量高达400000,所以使用邻接表储存图,然而题目要求的操作是每次去掉一个顶点,判断一次联通块数量,可以每次都去掉一个点,进行一次图遍历。复杂度太高,舍弃。技巧:反向操作,从一个已有的并查集中去除一个点非常难,但是加入一个点很简单,倒序将点加入,每次遍历加入的顶点的邻接表。最后倒序输出即为答案。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#define MAX 400010
using namespace std;

vector<int> vis[MAX];
int ans[MAX];
int rec[MAX];
bool node[MAX];
int fa[MAX];
int N,M;

int find(int x)
{
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void init()
{
    memset(node,0,MAX * sizeof(bool));
    for (int i = 0; i < N; ++i) fa[i] = i;
    for(int i = 1 ; i <= MAX ; i++) vis[i].clear();

    return ;

}

int main()
{
    while(~scanf("%d%d",&N,&M))
    {

        init();
        int a , b;
        for (int i = 1; i <= M ; ++i)
        {
            scanf("%d%d",&a,&b);
            vis[a].push_back(b);
            vis[b].push_back(a);

        }
        ///////////////////////////////////
        int case_num;
        scanf("%d",&case_num);
        int nodenum = N;
        for (int i = case_num - 1; i >= 0; i--)
        {
            scanf("%d",&rec[i]);
            node[rec[i]] = 1;
            nodenum--;
        }
        int key = 0;
        ans[key] = nodenum;
        /////////////////////////
        for (int i = 0; i < N; ++i)
        {
            a = i;
            for (int j = 0; j < vis[a].size(); ++j)
            {
                b = vis[a].at(j);
                if(node[a] || node[b]) continue;
                if(find(a) != find(b)) {find(a) < find(b) ? fa[find(b)] = find(a) : fa[find(a)] = find(b);ans[key]--;}
            }
        }

        ///////////////////////

        for (int i = 0; i < case_num; ++i)
        {
             key++;
             ans[key] = ans[key - 1] + 1;
             int a = rec[i];
             node[a] = 0;
             for (int j = 0; j < vis[a].size(); ++j)
             {
                 b = vis[a].at(j);
                 if(node[a] || node[b]) continue;
                 if(find(a) != find(b)) { find(a) < find(b) ? fa[find(b)] = find(a) : fa[find(a)] = find(b); ans[key]--;}
             }
        }
        for(int i = case_num ; i >= 0 ; i--)
            cout << ans[i] <<endl;

    }

    return 0;

}

 
 
时间: 2024-10-14 06:48:16

并查集初步题目(2)的相关文章

Num 21 : HDOJ: 题目1272 : 小希的迷宫 ( 并查集问题 )

题目: 小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 35368    Accepted Submission(s): 10808 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通

poj 1611 :The Suspects经典的并查集题目

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.   In the Not-Spr

并查集题目整理

并查集 之前写最小生成树的时候对这一部分的知识也并没有十分详细的整理 近天做了一些用到并查集的题目,来整理一下 知识回顾 首先,先来回顾一下有关并查集的内容 <1> 定义 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示. 集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并. <2>初始化 把每个点所在集合初始化为其自身. 通常来说,这个步骤在每次使用该数据结构时只需要执行

UVA12232 - Exclusive-OR(带权并查集)

题目:UVA12232 - Exclusive-OR(带权并查集) 题目大意:给你I P V 代表Xp 的值是V.或者 I P Q V 代表X P ^X i + 1 ^X i+2 ...^X^Q = V;然后给你Q k p1 p2 p3...pk问这些数字的异或值. 解题思路:这题首先要明确 x ^ y = V , x ^ z = W, 那么 y ^ z = V ^ W;  所以这题可以用并查集来做,因为只要两个数都和同一个数异或,那么他们就属于同一个集合,这样即使它们和一个数这个数的值是未知的

HDU 3635 延缓更新的并查集

Dragon Balls Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2839    Accepted Submission(s): 1097 Problem Description Five hundred years later, the number of dragon balls will increase unexpecte

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

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

Codeforces Round #254 (Div. 2) DZY Loves Chemistry【并查集基础】

一开始不知道题意是啥意思,迟放进去反应和后放进去反应有什么区别 对于第三组数据不是很懂,为啥312,132的组合是不行的 后来发现这是一道考察并查集的题目 QAQ 怒贴代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream> 6 #include <algorithm> 7

hdu1272并查集入门

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 41540    Accepted Submission(s): 12811 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是

poj1984 带权并查集(向量处理)

Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 5939   Accepted: 2102 Case Time Limit: 1000MS Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series o