[USACO21DEC] Connecting Two Barns S(连接两个牛棚)
题目描述
Farmer John 的农场由 \(N\) 块田地(\(1 \leq N \leq 10^5\))组成,编号为 \(1 \ldots N\)。在这些田地之间有 \(M\) 条双向道路(\(0 \leq M \leq 10^5\)),每条道路连接两块田地。
农场有两个牛棚,一个在田地 1 中,另一个在田地 \(N\) 中。Farmer John 希望确保有一种方式可以沿着一组道路在两个牛棚之间行走。 他愿意建造至多两条新道路来实现这一目标。由于田地的位置因素,在田地 \(i\) 和 \(j\) 之间建造新道路的花费是 \((i-j)^2\)。
请帮助 Farmer John 求出使得牛棚 \(1\) 和 \(N\) 可以相互到达所需要的最小花费。
输入格式
每个测试用例的输入包含 \(T\) 个子测试用例(\(1\le T\le 20\)),所有子测试用例必须全部回答正确才能通过整个测试用例。
输入的第一行包含 \(T\),之后是 \(T\) 个子测试用例。
每个子测试用例的第一行包含两个整数 \(N\) 和 \(M\)。以下 \(M\) 行,每行包含两个整数 \(i\) 和 \(j\),表示一条连接两个不同田地 \(i\) 和 \(j\) 的道路。输入保证任何两个田地之间至多只有一条道路,并且所有子测试用例的 \(N+M\) 之和不超过 \(5 \cdot 10^5\)。
输出格式
输出 \(T\) 行。第 \(i\) 行包含一个整数,为第 \(i\) 个子测试用例的最小花费。
样例输入
2
5 2
1 2
4 5
5 3
1 2
2 3
4 5
样例输出
2
1
样例解释
- 第一个子测试用例中,最优的方式是用一条道路连接田地 2 和 3,用一条道路连接田地 3 和 4。
- 第二个子测试用例中,最优的方式是用一条道路连接田地 3 和 4。不需要第二条道路。
数据范围
- 测试点 2 满足 \(N \le 20\)。
- 测试点 3-5 满足 \(N \le 10^3\)。
- 测试点 6-10 没有额外限制。
Solution:
因为建造至多两条新道路,故最优解可能会出现下列情况:
- 不连边:1号节点与n号节点联通
- 连1条边:1号节点与n号节点不联通,在它们所在的联通块中各选一个点进行连接
- 连2条边:1号节点与n号节点不联通,在它们所在的联通块中各选一个点与中转块(第3个联通块)中的点进行连接
可以发现,连1条边其实是连2条边的特殊情况:中转块为 1/n号节点的连通块
因此,可以枚举中转块,注意:不是中转点,因为连接 1号节点联通块和n号节点联通块的 可能不是同一节点
Code:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const ll INF=1e18;
int n,m;
int p[N];
ll f[N],g[N];
int find(int x){return x==p[x]?x:p[x]=find(p[x]);}
ll dis(int x,int y){return (ll)(x-y)*(x-y);}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(p,0,sizeof(p));
for(int i=1;i<=n;++i)p[i]=i;
int u,v;
for(int i=1;i<=m;++i)
{
scanf("%d%d",&u,&v);
p[find(u)]=find(v);
}
int x=find(1),y=find(n);
if(x==y)
{
puts("0");
continue;
}
vector<int> a,b;
for(int i=1;i<=n;++i)
{
if(find(i)==x)a.push_back(i);
if(find(i)==y)b.push_back(i);
}
memset(f,0x3f,sizeof(f));
memset(g,0x3f,sizeof(g));
ll ans=INF;
for(int i=1;i<=n;++i)
{
ll res1=INF,res2=INF;
int p=lower_bound(a.begin(),a.end(),i)-a.begin();
if(p<a.size())res1=min(res1,dis(a[p],i));
if(p>0)res1=min(res1,dis(a[p-1],i));
p=lower_bound(b.begin(),b.end(),i)-b.begin();
if(p<b.size())res2=min(res2,dis(b[p],i));
if(p>0)res2=min(res2,dis(b[p-1],i));
u=find(i);
f[u]=min(f[u],res1);
g[u]=min(g[u],res2);
}
for(int i=1;i<=n;++i)
if(find(i)==i)
ans=min(ans,f[i]+g[i]);
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号