E - Reachable Sethttp://E - Reachable Set
题意概述 :
给定一个无向图,
对于每个 ,解决以下问题:
-选择最少的一些顶点,使得删除这些顶点及其关联的所有边后 点1只能到达以内的所有点
牵制芝士 :头文件,建图,带权并查集
题解 :
首先,我们可以将题目拆成两部分
1 :判断一个点能不能实现目标
2 :对于能实现的点,计算答案
第一部分 :
可以用并查集来处理
只与比小的节点连边,并统计与
所在集合的节点数
由于只与比小的节点连边,所以集合中只会有小于等于
的节点
所以当且仅当点所在集合的节点数等于
时,点
才会与
都联通
第二部分 :
使用数组标记目前是否能从
直接扩展到点
表示
值为
的节点的个数
所有大于能扩展点,都需要被删除
因为只处理能实现目标的节点,所以答案就是
代码 :
#include<bits/stdc++.h>
using namespace std;
int n,m,fa[210000],sum[210000];
vector<int>a[210000];
bool vis[210000];
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void add(int x,int y)
{
int fax=find(x);
int fay=find(y);
if(fax>fay) swap(fax,fay);
if(fax!=fay)
{
sum[fax]+=sum[fay];
fa[fay]=fax;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
fa[i]=i;
sum[i]=1;
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
vis[1]=1;
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<a[i].size();j++)
{
if(a[i][j]<i) add(a[i][j],i);//第一部分
if(!vis[a[i][j]]) ans++;//第二部分
vis[a[i][j]]=1;
}
printf("%d\n",sum[1]!=i?-1:(ans-i));
}
return 0;
}