BZOJ 1015 JSOI2008 星球大战 starwar 并查集

题目大意:给定一个无向图,求联通块个数,以及k次每次摧毁一个点后的;联通块个数

将边和摧毁的点全记录下来,反着做即可。

注意被摧毁的点不能算作联通块

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 400400
using namespace std;
struct abcd{
	int to,next;
}table[M];
int head[M],tot;
int n,m,q;
int fa[M],stack[M],destroy[M],top,now;
bool destroyed[M];
int Find(int x)
{
	if(!fa[x]||fa[x]==x)
		return fa[x]=x;
	return fa[x]=Find(fa[x]);
}
inline void Unite(int x,int y)
{
	int fx=Find(x);
	int fy=Find(y);
	if(fx==fy)
		return ;
	--now;
	fa[fy]=fx;
}
inline void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
int main()
{
	int i,j,x,y;
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		++x;++y;
		Add(x,y);
		Add(y,x);
	}
	cin>>q;
	for(i=1;i<=q;i++)
	{
		scanf("%d",&destroy[i]);
		++destroy[i];
		destroyed[destroy[i]]=1;
	}
	now=n-q;
	for(j=1;j<=n;j++)
		if(!destroyed[j])
			for(i=head[j];i;i=table[i].next)
				if(!destroyed[table[i].to])
					Unite(j,table[i].to);
	stack[++top]=now;
	for(j=q;j;j--)
	{
		x=destroy[j];
		destroyed[x]=0;
		++now;
		for(i=head[x];i;i=table[i].next)
			if(!destroyed[table[i].to])
				Unite(x,table[i].to);
		stack[++top]=now;
	}
	while(top)
		printf("%d\n",stack[top--]);
}
时间: 2024-10-12 19:52:45

BZOJ 1015 JSOI2008 星球大战 starwar 并查集的相关文章

BZOJ 1015: [JSOI2008]星球大战starwar 并查集

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

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【并查集】

题目可以表述成:给定一个无向图G,每次删除它的一个点和与点相关的边集,每次询问该操作后图G的连通度(连通分量的个数).和上一题一样都是考察逆向思维,虽然删除点的做法不会,但是每次加点后询问连通度却是并查集的经典用法,所以答案可以逆过来推,具体做的时候每次加入一个点,将所有和这个点有边相连的点集合并,然后输出当前有多少个集合.细节部分需要注意的是由于点的数量十分庞大,邻接表是十分有必要的 #include<iostream> #include<cstdio> #include <

bzoj 1015: [JSOI2008]星球大战starwar

1 #include<cstdio> 2 #include<iostream> 3 #define M 2000000 4 int cnt,fa[M],n,m,ans[M],k,f[M],a[M],head[M],next[2*M],u[2*M]; 5 int zhao(int a1) 6 { 7 if(a1==fa[a1]) 8 return a1; 9 fa[a1]=zhao(fa[a1]); 10 return fa[a1]; 11 } 12 void jia(int a1,

BZOJ 1015 JSOI2008 星球大战 starwar 并检查集合

标题效果:给定一个无向图.联通谋求块的数目,以及k一个点的破坏后每次:联通,块的数目 侧面和摧毁的地步全记录,我们可以做相反的. 需要注意的是该点不能算作破坏联通块 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 400400 using namespace std; struct abcd{ int to,next; }table[M];

bzoj1015: [JSOI2008]星球大战starwar 并查集+离线处理

题目传送门 这道题可以改为离线处理 倒着找答案 这样删点就变成加点了 有了这个思想题目就很好写了哇 23333 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=400007; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=g

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--)

1015: [JSOI2008]星球大战starwar

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

【BZOJ】1015: [JSOI2008]星球大战starwar(并查集)

http://www.lydsy.com/JudgeOnline/problem.php?id=1015 看了题解的囧T_T,一开始以为是求割点,但是想到割点不能统计.... 这题用并查集,思想很巧妙. 我们按照逆序建图,也就是从最后一个毁了的星球之后建图.然后从后往前走. 那么怎么统计联通块呢?很简单,我们开个数组记录没有被破坏的星球,然后每一次都将一个星球拿去访问他连接的其他点,看他们是否在一个联通块,如果不是,那么就将连接的那个点加入自己的联通块. #include <cstdio> #