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

并查集本来就是连一对不同父亲的节点就的话连通块就少一个。

题目描述

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。

但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

输入输出格式

输入格式:

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

接下来的M行,每行包括两个整数X, Y,其中(0<=X<>Y<N),表示星球X和星球Y之间有以太隧道。注意所有的以太隧道都是双向的。

接下来一行是一个整数K,表示帝国计划打击的星球个数。

接下来的K行每行一个整数X,满足0<=X<N,表示帝国计划打击的星球编号。帝国总是按输入的顺序依次摧毁星球的。

输出格式:

输出文件的第一行是开始时星球的连通块个数。

接下来的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]

解答

参考洛谷题解

读完题目,我们首先会想到每次删去一个点,然后重新建图,算出联通块的个数。然而,这根本不信,时间上过不去,这时就得让我们将头旋转180度,从后往前处理,也就是我们经常用的接边了。当然,再接边前需要预处理,当前这条边应当在什么时候接上,给边标上序号,然后依次处理。最后逆序输出,就可以啦啦啦。如果还不懂,请看代码。

PS:帝国攻占的地盘不算是反抗军的地盘。

比较有趣的一道并查集。

我们在做组合数学或者集合的时候会说一句话,叫做正难则反。这里也是同样的。

首先,既然是对联通块的操作,那自然而然的想到用并查集解决。

先来思考一个问题:如果有n个块,然后我们要进行合并,合并之后有多少块?只需要对合并函数稍稍修改:

inline void uni(int x, int y) {
int xx = find(x), yy = find(y);
if(xx == yy) return;
--cnt;
fa[xx] = yy;
}

每一次合并,如果两个在同一集合中就不做处理,否则相当于连通块-1.

返回这道题,摧毁的过程是相当难以维护的,由于这道题是离线的,所以我们可以反过来重建。以样例为例,在摧毁的最后,节点0 2 4分别构成了3个连通块,注意这里答案并不是8,因为不存在剩下的5个节点!

然后每每恢复一个节点,就可以把和它相关联的连通块都合并一遍,但是要注意,这个时候的合并的前提,是对面重建过。实现见下。

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 200005
using namespace std;
int n,m,fa[MAXN*],K,D[MAXN*],vis[MAXN*],ans[*MAXN],num;
//num表示总联通块的个数,ans[]记住答案 ,vis[]给点标号 ,D[]被攻占的点
struct xcw{
int x,y,c;//x,y表示这条边的两端点,c表示这条边的序号
bool operator <(const xcw b)const{return c<b.c;}//按序号从小到大排序
}a[MAXN];
int read(){
int ret=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-f;ch=getchar();}
while(ch>=''&&ch<='') ret=ret*+ch-,ch=getchar();
return ret*f;
}
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
void mer(int x,int y){
int fx=get(x),fy=get(y);
if(fx!=fy) fa[fx]=fy,num--;//两联通块合并,总联通块num--
}
int main(){
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
n=read();m=read();num=n;
for(int i=;i<n;i++) fa[i]=i;
for(int i=;i<=m;i++) a[i]=(xcw){read(),read(),};
K=read();
for(int i=;i<=K;i++) vis[D[i]=read()]=K-i+;//给点标号,从大到小
for(int i=;i<=m;i++) a[i].c=max(vis[a[i].x],vis[a[i].y]);//当前边的序号是两个点中最大的那个
sort(a+,a++m);//给点按序号大小排序,方便处理,优化效率
for(int i=,j=;i<=K;i++){//枚举被攻占的星球序号
for(;a[j].c==i;j++) mer(a[j].x,a[j].y);//将当前序号全部合并
ans[i]=num-(K-i);//K-i是帝国攻占的星球个数(因为是逆序处理的)
}
for(int i=K;i>=;i--) printf("%d\n",ans[i]);//逆序输出
return ;
}

代码具体过程:

D[]数组
i D[i] vis[D[i]]
1 1 5
2 6 4
3 3 3
4 5 2
5 7 1
vis[]数组:
0 1 2 3 4 5 6 7
0 5 0 3 0 2 4 1
排序前:
i a[i].x a[i].y a[i].c
1 0 1 5
2 1 6 5
3 6 5 4
4 5 0 2
5 0 6 4
6 1 2 5
7 2 3 3
8 3 4 3
9 4 5 2
10 7 1 5
11 7 2 1
12 7 6 4
13 3 6 4
排序后:
i a[i].x a[i].y a[i].c
1 7 2 1
2 5 0 2
3 4 5 2
4 2 3 3
5 3 4 3
6 6 5 4
7 0 6 4
8 7 6 4
9 3 6 4
10 0 1 5
11 1 6 5
12 1 2 5
13 7 1 5
结果:
i num ans[i]
0 8 3
1 7 3
2 5 2
3 3 1
4 2 1
5 1 1
1
1
1
2
3
3

P1197 [JSOI2008]星球大战(并查集判断连通块+正难则反)的更多相关文章

  1. P1197 [JSOI2008]星球大战[并查集+图论]

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

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

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

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

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

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

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

  5. C. Edgy Trees Codeforces Round #548 (Div. 2) 并查集求连通块

    C. Edgy Trees time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  6. hdu--1878--欧拉回路(并查集判断连通,欧拉回路模板题)

     题目链接 /* 模板题-------判断欧拉回路 欧拉路径,无向图 1判断是否为连通图, 2判断奇点的个数为0 */ #include <iostream> #include <c ...

  7. BZOJ 1015: [JSOI2008]星球大战starwar(并查集求连通块+离线处理)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1015 题意: 思路:好题啊!!! 这道题目需要离线处理,先把所有要删的点给保存下来,然后逆序加点,这 ...

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

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

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

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

随机推荐

  1. [Luogu] P1441 砝码称重

    题目描述 现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0). 题目分析 因为读错题WAWA大哭. 先dfs枚举选的砝码,满足条件时进行d ...

  2. 笔试算法题(48):简介 - A*搜索算法(A Star Search Algorithm)

    A*搜索算法(A Star Search Algorithm) A*算法主要用于在二维平面上寻找两个点之间的最短路径.在从起始点到目标点的过程中有很多个状态空间,DFS和BFS没有任何启发策略所以穷举 ...

  3. win10 专业版 安装tornado 的步骤

    win10 专业版 安装tornado 的步骤: 1.下载tornado源码压缩包 下载网址:https://github.com/tornadoweb/tornado 若是没有github 账号可以 ...

  4. 安装配置elasticsearch、安装elasticsearch-analysis-ik插件、mysql导入数据到elasticsearch、安装yii2-elasticsearch及使用

    一.安装elasticsearch 获取elasticsearch的rpm:wget https://download.elastic.co/elasticsearch/release/org/ela ...

  5. YUM:Yellow dog Updater Modified

    1. 什么是YUM YUM(全称为 Yellow dog Updater Modified) 是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器.基于RPM包管理,能够从 ...

  6. PHP条件运算符的“坑”

    今天遇到一个关于PHP 嵌套使用条件运算符(ternary expressions)的问题 现象 先来看一段C语言代码(test.c): #include<stdio.h> int mai ...

  7. 安装bitcore

    官网----------------------------------------------https://bitcore.io先安装好 node.js v4,  npmsudo npm inst ...

  8. STM32F407 跑马灯 库函数版 个人笔记

    原理图: MCU在开发板原理图的第二页,LED在开发板原理图的第三页 由图可知,PF9 ,PF10 若输出低电平则灯亮,高电平则灯灭 选推挽输出 代码步骤 使能IO口时钟. 调用函数RCC_AHB1P ...

  9. 60. Spring Boot写后感【从零开始学Spring Boot】

    从2016年4月15日到2016年7月20日经历长达3个月的时间,[从零开始学习Spring Boot]系列就要告一段落了.国内的各种资源都比较乱或者是copy 来copy去的,错了也不加以修正下,导 ...

  10. 7-9 旅游规划(25 分)(Dijkstra最短路径算法)

    有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果有若干条路径都是最短的,那么需要输出最便 ...