虫洞(conch)
【题目描述】
HZY 现在在数轴原点处,她想跑到 2000001 这个点上。听说各路 神犇暑假里都在健♂身,所有 HZY 也想不要只是简单地跑步,于是她 决定在这条数轴上造虫洞,具体的,每次可以任选两个[1, 2000000] 之中的实数点,将它们用虫洞连接起来(为了避免不必要的时空错乱, 这两个点不能是同一个点,并且如果一个点已经和其它的点通过虫洞 相连,那就不能选)。 这样一来,在 HZY 跑步的过程中,一旦碰到了某个虫洞的一个端 口,就会从另一个端口出来,继续向正方向跑。 现在 HZY 已经建造了 n 个虫洞。她还想再建造 m 个虫洞,使得她 在跑步过程中穿过虫洞的次数最多。
【输入格式】 从文件 conch.in 中读入数据。 第一行一个整数 n,第二行一个整数 m。 接下来 m 行每行两个整数 a, b( a < b )描述一个已有虫洞的两个端 点。
【输出格式】 输出到文件 conch.out 中。 一行一个数表示再建造 m 个虫洞之后,最多的穿越次数。
input
3
1
10 11
1 4
2 3
output
6
input
3
1
1 3
4 6
2 5
output
8
n,m<=1000000
sol:先暴力走一遍,对于每个走过的虫洞的入口标记为已访问,再把走过的地方也标记为已访问,然后再扫一遍,可以算出没访问的就是一个个的环,每个环有不同贡献,按贡献大小造虫洞,如果m有多的就XJB特判一下
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar(' ') const int N=2000005; int n,m,Go[N],ans=0,Sum[N]; bool Vis[N]; inline int Play(int Pos) { int res=0; for(;Pos<=2000000&&(!Vis[Pos]);Pos++) { Vis[Pos]=1; if(Go[Pos]) { Pos=Go[Pos]; res++; } } return res; } int main() { freopen("conch.in","r",stdin); freopen("conch.out","w",stdout); int i; R(n); R(m); for(i=1;i<=n;i++) { int a,b; R(a); R(b); Go[a]=b; Go[b]=a; } for(i=1;i<=2000000;i++) { Vis[i]=1; if(Go[i]) {i=Go[i]; ans++;} } for(i=1;i<=2000000;i++) { if(!Vis[i]) Sum[++*Sum]=Play(i); } sort(Sum+1,Sum+*Sum+1); for(i=*Sum;i>=1;i--) { if(m) {ans+=Sum[i]+2; m--;} } if(m) ans+=(m<<1)-(m&1); Wl(ans); return 0; } /* input 3 1 10 11 1 4 2 3 output 6 input 3 1 1 3 4 6 2 5 output 8 */