TOU-Tour de Byteotia
这是一道相对裸的并查集。
因为洛谷题面本身就很简短,在这里就不再做题意简述,下面直接来讲做法。
思路简述
题目让我们求至少删掉多少条边能使得编号小于等于 \(k\) 的点都不在环上,而在并查集中删除并不好操作,于是我们考虑转化。
因为题目只是要求回答个数而非方案,所以我们可以把删点操作转化为计数,具体实现如下。
考虑到最初那个连通块在删去所有边之后,剩下的必然只有编号 \(x\) 满足大约 \(k\) 的点,于是我们在最初建图的时候可以先只把满足要求的点并在一起。
那么剩下的必然都是编号小于等于 \(k\) 的点,考虑如何选择能让题面中所述的删去点的次数更少。
在最坏的情况下,我们把每个点都删除一次。如果我们能利用题目中所给出的边把剩下的点并在一起,就能减少我们的删除操作次数从而减小答案。
Code
实际上面所述的内容用并查集实现很简单,于是下面的代码部分不做过多解释。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <string.h>
#define Heriko return
#define Deltana 0
#define Romanno 1
#define S signed
#define LL long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
template<typename J>
I void fr(J &x)
{
short f(1);
char c=getchar();
x=0;
while(c<'0' or c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while (c>='0' and c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
template<typename J>
I void fw(J x,bool k)
{
if(x<0) putchar('-'),x=-x;
static short stak[35];
short top(0);
do
{
stak[top++]=x%10;
x/=10;
}
while(x);
while(top) putchar(stak[--top]+'0');
if(k) putchar('\n');
else putchar(' ');
}
CI MXX=8e5+5;
int n,m,k,f[MXX],ans;
struct line
{
int x,y;
}
r[MXX];
I int Find(const int &x)
{
if(x!=f[x]) f[x]=Find(f[x]);
Heriko f[x];
}
S main()
{
fr(n),fr(m),fr(k);
for(R int i(1);i<=n;++i) f[i]=i;
for(R int i(1);i<=m;++i) fr(r[i].x),fr(r[i].y);
for(R int i(1);i<=m;++i) if(r[i].x>k and r[i].y>k) f[Find(r[i].x)]=Find(r[i].y);
for(R int i(1);i<=m;++i)
{
int fx=Find(r[i].x),fy=Find(r[i].y);
if(r[i].x<=k or r[i].y<=k)
{
if(fx!=fy) f[fx]=fy;
else ++ans;
}
}
fw(ans,1);
Heriko Deltana;
}
希望大家能有所收获。
审核的管理员辛苦了!