【反向并查集、联通图】P1197 [JSOI2008]星球大战
题目描述
很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系。
某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。
但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。
现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。
输入输出格式
输入格式:
输入文件第一行包含两个整数,NN (1 < = N < = 2M1<=N<=2M) 和 MM (1 < = M < = 200,0001<=M<=200,000),分别表示星球的数目和以太隧道的数目。星球用 00 ~ N-1N−1 的整数编号。
接下来的 MM 行,每行包括两个整数 XX, YY,其中( 0 < = X <> Y0<=X<>Y 表示星球 xx 和星球 yy 之间有 “以太” 隧道,可以直接通讯。
接下来的一行为一个整数 kk ,表示将遭受攻击的星球的数目。
接下来的 kk 行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这 kk 个数互不相同,且都在 00 到 n-1n−1的范围内。
输出格式:
第一行是开始时星球的连通块个数。接下来的 KK 行,每行一个整数,表示经过该次打击后现存星球的连通块个数。
样例太占地方就不放了。
这道题是在洛谷刷并查集时遇到的,所以看到的时候想了一下就知道是反向并查集了。
简单的建图保存边,还有并查集的基本操作。需要注意的是计算出联通块的数量后,在结果上要减去已经爆炸的星星数量(爆炸后是孤立的点);
以及在从后往前计算的过程中,没计算完一颗星星,要记得把Is_Lose[]的值刷新,因为计算前i 次爆炸时,后面的星星依然存在。
剩下的就是些基本操作了,做完才发现是道水题。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int Max_E= ;
const int Max_V= ;
struct ENode
{
int to;
int Next;
};
ENode Edegs[Max_E];
int Head[Max_V];
int tnt= -;
void Add_ENode (int u, int v)
{
++ tnt;
Edegs[tnt].to= v;
Edegs[tnt].Next= Head[u];
Head[u]= tnt;
}
int pre[Max_V];
void into(int N)
{
for (int i= ; i<= N; i ++)
{
pre[i]= i;
Head[i]= -;
}
}
int find_F (int x)
{
int r= x;
while (r!= pre[r])
{
r= pre[r];
}
int i= x, j;
while (i!= r)
{
j= pre[i];
pre[i]= r;
i= j;
}
return r;
}
void join (int x, int y)
{
int a= find_F(x);
int b= find_F(y);
if (a!= b) pre[a]= b;
}
int It_Lose[Max_V]; //按顺序依次记录被炸掉的行星
bool Is_Lose[Max_V];//标记行星此刻是否被炸毁
int Is_Many[Max_V]; //记录第Ki时联通块的个数
int pre1[Max_V]; // copy 一下 pre[];
int main()
{
int n, m;
int a, b;
cin >>n >>m;
into(n);
tnt= -;
while (m --)
{
cin >>a >>b;
Add_ENode(a, b);
Add_ENode(b, a);
}
int k, c;
memset(Is_Lose, false, sizeof(Is_Lose));
cin >>k;
for (int j= ; j<= k; j ++)
{
cin >>c;
It_Lose[j]= c;
Is_Lose[c]= true;
}
for (int i= ; i< n; i ++)
{
if (Is_Lose[i]) continue;
for (int j= Head[i]; j!= -; j= Edegs[j].Next)
{
int v= Edegs[j].to;
if (! Is_Lose[v]) join(v, i);
}
}
/*copy 一下pre[], 然后对pre1[]排序*/
for (int i= ; i< n; i ++) pre1[i]= find_F(i);
sort(pre1, pre1+ n);
int cnt= , ans;
/*遍历排序后的pre1[],计算出有多少个根节点不同的点,
即几个块联通块*/
for (int i= ; i< n; i ++)
{
if (! i)
{
ans= pre1[i];
continue;
}
if (pre1[i]!= ans) ans= pre1[i], ++ cnt;
}
/*最后一次,即第k 次爆炸后剩余的不联通的星系数量,
等于此时总联通块的数量减去已经爆炸的星星,即减k */
Is_Many[k]= cnt- k; /*从后往前遍历炸毁的星星,开始添点接边,反向并查集*/
for (int i= k- ; i>= ; i --)
{
/*第i 颗星星爆炸后的联通块数量,
即加上第i+ 1颗星星后的联通块数量*/
int u= It_Lose[i+ ];
Is_Lose[u]= ; //在这次计算时,u还未被炸毁
for (int j= Head[u]; j!= -; j= Edegs[j].Next)
{
/*遍历第i+ 1颗星星的所有边,接边。*/
int v= Edegs[j].to;
if (Is_Lose[v]) continue;
/*若边连接的终点未被炸毁,
判断终点与起点的根节点是否相同,若不相同,
证明两个本不联通的块被联通,计数器cnt减1*/
if (find_F(v)!= find_F(u)) join(v, u), --cnt;
}
Is_Many[i]= cnt- i; //记得减去已被炸毁的星星
}
/*输出结果w*/
for (int i= ; i<= k; i ++)
{
cout << Is_Many[i] << endl;
}
return ;
}
end;
【反向并查集、联通图】P1197 [JSOI2008]星球大战的更多相关文章
- P1197 [JSOI2008]星球大战 并查集 反向
题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...
- P1197 [JSOI2008]星球大战(并查集判断连通块+正难则反)
P1197 [JSOI2008]星球大战(并查集判断连通块+正难则反) 并查集本来就是连一对不同父亲的节点就的话连通块就少一个. 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统 ...
- html5 canvas程序演示--P1197 [JSOI2008]星球大战
html5 canvas程序演示--P1197 [JSOI2008]星球大战 <!doctype html> <html> <head> <meta char ...
- 洛谷P1197 [JSOI2008] 星球大战 [并查集]
题目传送门 星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这 ...
- P1197 [JSOI2008]星球大战[并查集+图论]
题目来源:洛谷 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球 ...
- Bzoj1015/洛谷P1197 [JSOI2008]星球大战(并查集)
题面 Bzoj 洛谷 题解 考虑离线做法,逆序处理,一个一个星球的加入.用并查集维护一下连通性就好了. 具体来说,先将被消灭的星球储存下来,先将没有被消灭的星球用并查集并在一起,这样做可以路径压缩,然 ...
- PAT甲题题解-1126. Eulerian Path (25)-欧拉回路+并查集判断图的连通性
题目已经告诉如何判断欧拉回路了,剩下的有一点要注意,可能图本身并不连通. 所以这里用并查集来判断图的联通性. #include <iostream> #include <cstdio ...
- Educational Codeforces Round 64 (Rated for Div. 2)D(并查集,图)
#include<bits/stdc++.h>using namespace std;int f[2][200007],s[2][200007];//并查集,相邻点int find_(in ...
- 长春理工大学第十四届程序设计竞赛A Rubbish——并查集&&联通块
题目 链接 题意:在 $10^5 \times 10^5$ 的大网格上,给出 $n$ 的格点的坐标,求联通块数(上下左右及对角线都认为相邻) 分析 DFS需要遍历网格的每个格点,可能会超时? 初始化时 ...
随机推荐
- 容器HashMap原理(学习)
一.概述 基于哈希表的 Map 接口的非同步实现,允许使用 null 值和 null 键,不保证映射的顺序 二.数据结构 HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体:Has ...
- Cocos2d-x 3.2编译生成Android程序出错Error running command, return code: 2的解决方法
用Cocos2d-x 3.2正式版创建项目,结果使用cocos compile -p android编译生成APK程序,结果悲剧了,出现以下错误. Android NDK: Invalid APP_S ...
- [NOI2018]冒泡排序
https://www.zybuluo.com/ysner/note/1261482 题面 戳我 \(8pts\ n\leq9\) \(44pts\ n\leq18\) \(ex12pts\ q_i= ...
- TI BLE:SCAN
主机会运行SCAN来搜寻广播中的设备 运行函数: GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE, DEFAULT_DISCOVERY_AC ...
- PCB .NET Reactor 加密工具(NecroBit加密技术)
在PCB行业中,我们使用的软件或脚本绝大多数都用非编译型语言写程序,而从一开始选择这种编程语言,就注定了程序的源码有被曝露风险.我们PCB工程系统用.NET语言编写,C#编译后会被转换为IL代码的中间 ...
- 人脸识别(初学篇)-VS2015+opencv3.2的配置
初学人脸识别,感觉安装也是一个很大的麻烦. 写在这里记录一下吧 一:先安装好我们需要的软件 首先安装Vs2015,在官网或者csdn搜一下应该找的到. 安装步骤没有太多讲究. 点击exe文件,我选择的 ...
- Androidstudio的安装与使用调试
1安装与基本使用 1.1androidstudio的安装 1.到android-studio\bin文件夹里面,根据自己的电脑配置,打开studio.exe或者studio64.exe 2.按照向导默 ...
- 2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛-K-Matrix Multiplication(矩阵乘法)
题目描述 In mathematics, matrix multiplication or matrix product is a binary operation that produces a m ...
- Android 性能优化(12)网络优化( 8)Monitoring the Battery Level and Charging State
Monitoring the Battery Level and Charging State PreviousNext This lesson teaches you to Determine th ...
- 转 linux shell自定义函数(定义、返回值、变量作用域)介绍
linux shell 可以用户定义函数,然后在shell脚本中可以随便调用.下面说说它的定义方法,以及调用需要注意那些事项. 一.定义shell函数(define function) 语法: [ f ...