题目来源:洛谷

题目描述

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系。

某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。

但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。

现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

输入输出格式

输入格式:

输入文件第一行包含两个整数,N (1<=N<=2M) 和 M (1<=M<=200,000),分别表示星球的数目和以太隧道的数目。星球用 0 ~ N-1 的整数编号。

接下来的 M 行,每行包括两个整数 X, Y,其中( 0<=X<>Y 表示星球 xx 和星球 yy 之间有 “以太” 隧道,可以直接通讯。

接下来的一行为一个整数 k ,表示将遭受攻击的星球的数目。

接下来的 k 行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这 k 个数互不相同,且都在 0 到 n−1的范围内。

输出格式:

第一行是开始时星球的连通块个数。接下来的 K 行,每行一个整数,表示经过该次打击后现存星球的连通块个数。

输入输出样例

输入样例#1:

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
输出样例#1:

1
1
1
2
3
3

说明

[JSOI2008]

这道题十分考验代码力和思维,需要对并查集和图论理解深入。

解析:

看到这题,我们如果按照题目意思理解,也可以很容易得到思路,只要建一个并查集,维护联通块就可以了。

但是根据题意,我们要从中删点,并在每次删完点之后统计联通块数量。

这就很令人头大了,我们知道,并查集并查集,合并容易删除难啊,这可怎么办呐?

没错,你可能已经想到了,既然合并比删除容易,那我们不妨倒转思路,逆向求解。

我们把题目改一下,姑且就叫它“反抗军重建计划”好了qwq:

很久以前,在一个遥远的星系,反抗军为了弥补之前帝国军队攻击的损失,开始了重建计划。

现在,反抗军首领交给你一个任务:给出将要重建的星球和重建计划中所有星球与其它星球之间的以太隧道,以尽量快的速度求出每重建完一个星球之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

嘿嘿,这是不是简单多了?而且跟原题正好反过来,求得的解也正好逆序。

思路还是差不多,每次重建星球后,将该星球与计划中要联通的星球合并入并查集中,这道题就完成了。

但是这里要提一个点,关于邻接表。在本题中,我们当然可以把所有星球看做一个无向图,并用邻接表储存。

但是实际上我们可以这样理解:邻接表中的表头可以用于表示某一个将要重建的星球与其它星球的联通关系。

参考代码:

 //反抗军重建计划qwq
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#define N 100010
using namespace std;
//邻接表存图
struct node{
int next,ver,from;
}g[N<<];
int n,m,k,tot;
int head[N<<],ans[N<<],fa[N<<],b[N<<];
bool v[N<<];//是否需要重建
void add(int x,int y)
{
g[++tot].ver=y,g[tot].from=x;
g[tot].next=head[x],head[x]=tot;
}
int get(int x)
{
if(fa[x]==x) return x;
return fa[x]=get(fa[x]);
}
void merge(int x,int y)
{
x=get(x),y=get(y);
if(x!=y) fa[x]=y;
}
int main()
{
memset(v,,sizeof(v));
memset(b,,sizeof(b));
scanf("%d%d",&n,&m); for(int i=;i<n;i++) fa[i]=i;//初始化 for(int i=;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
scanf("%d",&k);
//需要重建的星球
for(int i=;i<=k;i++){
scanf("%d",&b[i]);
v[b[i]]=;//记录一下该星球需要重建
}
int cnt=n-k;
//还没重建,我们就先联通起来没被摧毁的星球
//如果两个星球都存在,也就是都不用重建时,合并
for(int i=;i<=*m;i++){
if(!v[g[i].ver]&&!v[g[i].from]&&get(g[i].from)!=get(g[i].ver)){
cnt--;merge(g[i].from,g[i].ver);
}
}
//从后往前将摧毁的星球建回去
ans[k+]=cnt;
for(int i=k;i>=;i--){
//统计联通块个数
cnt++;v[b[i]]=;
for(int j=head[b[i]];j;j=g[j].next){
if(!v[g[j].ver]&&get(g[j].from)!=get(g[j].ver)){
cnt--;merge(b[i],g[j].ver);
}
}
ans[i]=cnt;
}
for(int i=;i<=k+;i++) printf("%d\n",ans[i]);
return ;
}

P1197 [JSOI2008]星球大战[并查集+图论]的更多相关文章

  1. 洛谷P1197 [JSOI2008] 星球大战 [并查集]

    题目传送门 星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这 ...

  2. P1197 [JSOI2008]星球大战 并查集 反向

    题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...

  3. 洛谷 P1197 [JSOI2008]星球大战——并查集

    先上一波题目 https://www.luogu.org/problem/P1197 很明显删除的操作并不好处理 那么我们可以考虑把删边变成加边 只需要一波时间倒流就可以解决拉 储存删边顺序倒过来加边 ...

  4. JSOI2008 星球大战 [并查集]

    题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...

  5. [bzoj1015][JSOI2008]星球大战——并查集+离线处理

    题解 给定一张图,支持删点和询问连通块个数 按操作顺序处理的话要在删除点的同时维护图的形态(即图具体的连边情况),这是几乎不可做的 我们发现,这道题可以先读入操作,把没删的点的边先连上,然后再倒序处理 ...

  6. P1197 [JSOI2008]星球大战(并查集判断连通块+正难则反)

    P1197 [JSOI2008]星球大战(并查集判断连通块+正难则反) 并查集本来就是连一对不同父亲的节点就的话连通块就少一个. 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统 ...

  7. html5 canvas程序演示--P1197 [JSOI2008]星球大战

    html5 canvas程序演示--P1197 [JSOI2008]星球大战 <!doctype html> <html> <head> <meta char ...

  8. Bzoj1015/洛谷P1197 [JSOI2008]星球大战(并查集)

    题面 Bzoj 洛谷 题解 考虑离线做法,逆序处理,一个一个星球的加入.用并查集维护一下连通性就好了. 具体来说,先将被消灭的星球储存下来,先将没有被消灭的星球用并查集并在一起,这样做可以路径压缩,然 ...

  9. 【反向并查集、联通图】P1197 [JSOI2008]星球大战

    题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...

随机推荐

  1. 容器服务如何在企业客户落地?Rancher 解决之道分享

    Docker 的优势和趋势我想不必再赘述,那么对于非互联网公司的传统企业客户,以及我们大量的围绕企业客户做集成.交付解决方案的服务提供商,需要考虑的一个问题就是怎么样把容器技术以高质量.低成本.易维护 ...

  2. obj.GetType().GetCustomAttributes

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. noi openjudge 1768:最大子矩阵

    链接:http://noi.openjudge.cn/ch0406/1768/ 描述已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如 ...

  4. (三)Python知识图谱

    查看大图

  5. PAT 1093

    The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the 4th, and ...

  6. C++ 工程师养成 每日一题third (子数列排序)

    题目: 定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序的.牛牛有一个长度为n的整数数组A,他现在有一个任务是把数组A分为若干段排序子序列,牛牛想知道他最少可以把这个数 ...

  7. python 职责链模式

    模式定义 责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链. 这种模式给予请求的类型,对请求的发送者和接收者进行解耦. 这种类型的设计模式属于 ...

  8. day24——面向对象三大特性、鸭子类型、类的约束、super的深度解析

    day24 面向对象的三大特性 继承.封装.多态 封装:把一堆东西(代码,数据)放到一个地方(空间),并且可以使用 class Student: def __init__(self, name, se ...

  9. sizeof运算符和strlen()函数

    首先放上代码和运行结果.(在VC6.0上运行) #include<stdio.h> #include<string.h> int main(void) { char s1[]= ...

  10. 【LEETCODE】72、分割回文串 III 第1278题

    package y2019.Algorithm.dynamicprogramming.hard; /** * @Auther: xiaof * @Date: 2019/12/11 08:59 * @D ...