7221. 【USACO 2021 US Open, Gold】Portals
Description&Data Constraint
Bessie 位于一个由 \(N\) 个编号为 \(1\dots N \) 的结点以及 \(2N\) 个编号为 \(1\cdots 2N\) 的传送门所组成的网络中。每个传送门连接两个不同的结点 \(u\) 和 \(v\)(\(u≠v\))。可能有多个传送门连接同一对结点。
每个结点 \(v\) 与四个不同的传送门相连。与 \(v\) 相连的传送门列表由 \(p_v=[p_{v,1},p_{v,2},p_{v,3},p_{v,4}]\) 给出。
你的当前位置可以用有序对(当前结点,当前传送门)表示;即一个有序对 \((v,p_{v,i})\),其中 \(1\le v\le N\) 以及 \(1\le i\le 4\)。你可以使用以下任一操作来改变你的当前位置:
- 由穿过当前传送门来改变当前结点。
- 改变当前传送门。在每一个结点上,列表的前两个传送门是配对的,后两个传送门也是配对的。也就是说,如果你的当前位置是 \((v,p_{v,2})\),你可以转而使用传送门 \((v,p_{v,1})\),反之亦然。类似地,如果你的当前位置是 \((v,p_{v,3})\),你可以转而使用传送门 \((v,p_{v,4})\),反之亦然。没有其他改变传送门的方式(例如,你不能从传送门 \(p_{v,2}\) 转去传送门 \(p_{v,4}\) )。
总共有 \(4N\) 个不同的位置。不幸的是,并不一定每一个位置都可以从另外的每一个位置经过一系列操作而到达。所以,以 \(c_v\) 哞尼的代价,你可以以任意顺序重新排列与 \(v\) 相邻的传送门列表。在此之后,列表中的前两个传送门互相配对,同时后两个传送门也互相配对。
例如,如果你将与 vv 相邻的传送门以 \([p_{v,3},p_{v,1},p_{v,2},p_{v,4}]\) 的顺序重新排列,这意味着如果你位于结点 \(v\) ,
- 如果你当前位于传送门 \(p_{v,1}\) ,你可以转而使用传送门 \(p_{v,3}\),反之亦然。
- 如果你当前位于传送门 \(p_{v,2}\) ,你可以转而使用传送门 \(p_{v,4}\),反之亦然。
- 你不再能够从传送门 \(p_{v,1}\) 转至传送门 \(p_{v,2}\),或从传送门 \(p_{v,3}\) 转至 \(p_{v,4}\) ,反之亦然。
计算修改这一网络使得每一个位置都可以从另外的每一个位置到达所需要花费的哞尼的最小数量。输入保证存在至少一种修改网络的合法方式。
\(2\le N \le 10^5,\le c_v\le 10^3\)。
Solution
首先由于初始状态下 1、2 号传送门和 3、4 号传送门是不通的,因此把一个点拆成两个点。
由于每个点的度都为 2,因此易证所有连通块都是环。
最终的情况就是所有点组成一个大环。
如何将两个环合并呢?
可以将原点和拆点连起来!这代表着更改此点的顺序。
同时将原点和拆点连起来是可以保证正确的,因为原点和拆点都可以各保留一个点,连上对方的剩余点,这样就成功的将两个环合并。
那么最小的代价,可以将每个\(c_v\) 从小到大排序,然后按顺序依次合并环,是否在一个环上可以用并查集。
本人有点傻,直接打了最小生成树,也是可以的。
Code
#include<cstdio>
#include<algorithm>
#define N 200005
using namespace std;
struct node
{
int x,y,v;
}edge[N*10];
int n,m,ans,c[N],x1[N],x2[N],x3[N],x4[N],f[N<<1];
bool bj[N<<1];
bool cmp(node x,node y) {return x.v<y.v;}
int find(int x)
{
if (f[x]!=x) f[x]=find(f[x]);
return f[x];
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d%d%d%d%d",&c[i],&x1[i],&x2[i],&x3[i],&x4[i]);
if (!bj[x1[i]]) edge[x1[i]].x=i,bj[x1[i]]=true;
else edge[x1[i]].y=i;
if (!bj[x2[i]]) edge[x2[i]].x=i,bj[x2[i]]=true;
else edge[x2[i]].y=i;
if (!bj[x3[i]]) edge[x3[i]].x=i+n,bj[x3[i]]=true;
else edge[x3[i]].y=i+n;
if (!bj[x4[i]]) edge[x4[i]].x=i+n,bj[x4[i]]=true;
else edge[x4[i]].y=i+n;
}
m=2*n;
for (int i=1;i<=n;++i)
edge[++m].x=i,edge[m].y=i+n,edge[m].v=c[i];
for (int i=1;i<=2*n;++i)
f[i]=i;
sort(edge+1,edge+1+m,cmp);
for (int i=1;i<=m;++i)
{
int x=find(edge[i].x),y=find(edge[i].y);
if (x!=y)
{
ans+=edge[i].v;
f[x]=y;
}
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号