Luogu P1197 [JSOI2008]星球大战 By cellur925

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

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

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

删边不如加边--LVYOUYW。

当我们看到联通块,我们眼前一亮,脑海里闪过了并查集。可是我们如何维护每次删边的操作,看起来很复杂的样子。

我们不妨换个思路,先求最后所有边都被摧毁的情况,也就求出了最后一种情况的答案,再一点点的加边。因为我们会加边操作,不会删边操作啊!于是,这个离线算法就确定了。

具体操作:断边、连边,我们听起来是图论的样子,但在本题中实质就是在并查集中将他们合并/拆散。最开始的情况我们先用邻接表存好,而是否在集合的信息用并查集维护。

这样,当我们再读入需要断边的消息时,不断,而是默默记录。我们首先要意识到,加边联通块减少,断边联通块增多。这样我们就可以倒着遍历需要断的节点,并遍历与其相连的所有边。

code

 1 #include<cstdio>
 2 #include<algorithm>
 3
 4 using namespace std;
 5
 6 int n,m,cnt,tot,x,y,k,head[400090],ans[400090],f[400090],flag[400090],mark[400090];
 7 struct node{
 8     int to,next,from;
 9 }edge[400090];
10
11 int getf(int x)
12 {
13     if(f[x]==x) return f[x];
14     return f[x]=getf(f[x]);
15 }
16
17 void merge(int x,int y)
18 {
19     int pp=getf(x);
20     int qq=getf(y);
21     if(pp!=qq) f[qq]=pp;
22 }
23
24 void add(int x,int y)
25 {
26     edge[++cnt].to=y;
27     edge[cnt].from=x;//不同于普通的邻接表,这里我们多维护了一个信息。
28     edge[cnt].next=head[x];
29     head[x]=cnt;
30  }
31
32 int main()
33 {
34     scanf("%d%d",&n,&m);
35     for(int i=0;i<=n;i++) f[i]=i,head[i]=-1;
36     //初始化很重要!节点编号从0开始,head要设为-1
37     //另外注意初始化的位置(滑稽
38     for(int i=1;i<=m;i++)
39     {
40         scanf("%d%d",&x,&y);
41         add(x,y);
42         add(y,x);
43     }
44     scanf("%d",&k);
45     for(int i=1;i<=k;i++)
46     {
47         scanf("%d",&x);
48         flag[x]=1;
49         mark[i]=x;
50     }
51     tot=n-k;//开始各点为一独立的联通块
52     for(int i=1;i<=2*m;i++)
53     {
54         if(!flag[edge[i].to]&&!flag[edge[i].from]&&getf(edge[i].to)!=getf(edge[i].from))
55          merge(edge[i].to,edge[i].from),tot--;
56          //每连一边,联通块便减少一点点
57     }
58     ans[k+1]=tot;
59     for(int i=k;i>=1;i--)
60     {
61         tot++;int p=mark[i];flag[p]=0;
62         //当前未连时的点是一个独立的联通块
63         for(int j=head[p];j!=-1;j=edge[j].next)
64         {//head意义改变,这里也就变了,注意!
65             if(!flag[edge[j].to]&&getf(edge[j].to)!=getf(p))
66              tot--,merge(edge[j].to,p);
67         }
68         ans[i]=tot;
69     }
70     for(int i=1;i<=k+1;i++) printf("%d\n",ans[i]);
71     return 0;
72 } 

附:并查集求联通块个数

https://blog.csdn.net/rcy_zhu/article/details/77622043

原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9374965.html

时间: 2024-10-12 22:44:32

Luogu P1197 [JSOI2008]星球大战 By cellur925的相关文章

[Luogu 1197] JSOI2008 星球大战

[Luogu 1197] JSOI2008 星球大战 <题目链接> 我算是真的沦为联赛选手了. 并查集裸题. 比较麻烦的是删点. 但是从后往前加点就好操作很多. 所以考虑离线,先存图,然后没被删的点之间,有边就合并. 每加一个点进来,把连着这个点且当前没被删的点并进来,更新连通块个数并存入答案. 最终按顺序输出答案即可. #include <cstdio> #include <cstring> const int MAXN=400010,MAXM=200010; boo

洛谷P1197 [JSOI2008]星球大战

题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重新造出了他的超级武器.凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球.由于星球的不断被摧毁,两个星球之 间的通讯通道也开始不可靠起来.现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速

P1197 [JSOI2008]星球大战

题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重新造出了他的超级武器.凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球.由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来.现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度

洛谷 P1197 [JSOI2008]星球大战

题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重新造出了他的超级武器.凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球.由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来.现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度

P1197 [JSOI2008]星球大战 [删边求连通块个数]

展开 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重新造出了他的超级武器.凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球.由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来. 现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽

luoguP1197 [JSOI2008]星球大战 x

P1197 [JSOI2008]星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重新造出了他的超级武器.凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球.由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来.现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通

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

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

【BZOJ 1015】[JSOI2008]星球大战starwar

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

bzoj1015:1015: [JSOI2008]星球大战starwar

应该是全部读入之后再添加边用并查集就可以了. yyl用空间换时间.u[]v[]等将边预存起来. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--)