一道并查集,最开始的思想是从1-n加边,前k个点有环就删,后面的点有环的话就判断是否和前k个点任意一个在一个集合中,但这样是错的,因为可能后面的点有环又与前k个点相连,有可能不影响,于是转换一下思路吧,先把不会影响的环加上就好了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=100000+10,maxm=200000+10;
int n,m,k,size=0;
int u[maxm],v[maxm],first[maxn],next[maxm],f[maxn],color[maxn];
bool vis[maxm],hash[9999999];
void init()
{
freopen("tyvj2066.in","r",stdin);
freopen("tyvj2066.out","w",stdout);
}
void insert(int x,int y)
{
size++;
u[size]=x;
v[size]=y;
next[size]=first[x];
first[x]=size;
}
int wori(int x)
{
int cnt=0;
while(x)
{
cnt++;
x/=10;
}
int ans=1;
for(int i=1;i<=cnt;i++) ans*=10;
return ans;
}
bool wocao(int x,int y)
{
int z=x*wori(y)+y,z1=y*wori(x)+x;
if(hash[z] || hash[z1]) return false;
else return true;
}
void readdata()
{
memset(next,0xff,sizeof(next));
memset(first,0xff,sizeof(first));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y || !wocao(x,y)) continue;
insert(x,y);
insert(y,x);
hash[x*wori(y)+y]=true;
hash[y*wori(x)+x]=true;
}
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=k;i++) color[i]=1;
for(int i=k+1;i<=n;i++) color[i]=2;
}
int find(int x)
{
return f[x] == x ? x : f[x]=find(f[x]);
}
void work()
{
int ans=0;
for(int i=k+1;i<=n;i++)
{
for(int e=first[i];e!=-1;e=next[e])
{
if(color[v[e]]==1) continue;
if(vis[e] || vis[e+1]) continue;
vis[e]=true;vis[e+1]=true;
int fx=find(i),fy=find(v[e]);
if(fx!=fy) f[fx]=fy;
}
}
for(int i=1;i<=k;i++)
{
for(int e=first[i];e!=-1;e=next[e])
{
if(vis[e] || vis[e+1]) continue;
vis[e]=true;vis[e+1]=true;
int fx=find(i),fy=find(v[e]);
if(fx!=fy) f[fx]=fy;
else ans++;
}
}
printf("%d\n",ans);
}
int main()
{
init();
readdata();
work();
return 0;
}