您的位置:首页 > Web前端 > JavaScript

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

2016-07-28 22:47 519 查看
题目大意:

给出一些点和一些边,每次删掉一个点和其连接的边

求每次删除一个点后图中的连通块个数

可以倒过来做并查集。

先按照输入建好一个虚拟的图

再把最后存在的星球之间的边连起来用并查集求出连通块个数

然后按照被攻击星球的逆序不断向图里加入点和边(加入的边的to[i]一定是图中存在的点),每一次用并查集更新连通块个数

按照顺序输出答案

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=400005;
int n,m,Q;
int D
,da
,ans;
bool b
,used
;
int cnt,to
,nxt
,lj
;
void add(int f,int t)
{
to[++cnt]=t;
nxt[cnt]=lj[f];
lj[f]=cnt;
}
int fa
;
int find(int x)
{
if(fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
void insert(int x)
{
int a=find(x);
for(int i=lj[x];i;i=nxt[i])
if(used[to[i]]==true)//若to[i]在图中
{
int c=find(to[i]);
if(a!=c) fa[c]=a,ans--;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
x++,y++;
add(x,y),add(y,x);
}
scanf("%d",&Q);
for(int i=1;i<=Q;i++)//离线
{
scanf("%d",&D[i]);
D[i]++;
b[D[i]]=true;
}
for(int i=1;i<=n;i++)//用最后存在的星球建图
if(b[i]==false)
{
ans++;
insert(i);
used[i]=true;
}
da[Q+1]=ans;
for(int i=Q;i>=1;i--)//逆序加入被攻击的星球
{
ans++;
insert(D[i]);
used[D[i]]=true;
da[i]=ans;
}
for(int i=1;i<=Q+1;i++) printf("%d\n",da[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息