这个东西我自己也不知道怎么精简,所以直接贴原题题面了。
题意
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\) 相邻的传送门列表。在此之后,列表中的前两个传送门互相配对,同时后两个传送门也互相配对。
例如,如果你将与 \(v\) 相邻的传送门以 \([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}\) ,反之亦然。
计算修改这一网络使得每一个位置都可以从另外的每一个位置到达所需要花费的哞尼的最小数量。输入保证存在至少一种修改网络的合法方式。
输入格式
输入的第一行包含 \(N\)。
以下 \(N\) 行每行描述一个结点。第 \(v+1\) 行包含五个空格分隔的整数 \(c_v,p_{v,1},p_{v,2},p_{v,3},p_{v,4}\)。
输入保证对于每一个 \(v\) ,\(p_{v,1},p_{v,2},p_{v,3},p_{v,4}\) 各不相同,且每个传送门出现在恰好两个结点的邻接表中。
输出格式
输出一行,包含修改这一网络使得每一个位置都可以从另外的每一个位置到达所需要花费的哞尼的最小数量。
输入输出样例 #1
输入 #1
5
10 1 4 8 9
11 1 2 5 6
12 9 10 2 3
3 4 3 6 7
15 10 8 7 5
输出 #1
13
说明/提示
样例解释
重新排列结点 \(1\) 和 \(4\) 的邻接表就已足够。这需要总计 \(c_1+c_4=13\) 哞尼。我们可以使 \(p_1=[1,9,4,8]\) 以及 \(p_4=[7,4,6,3]\)。
数据范围与约定
\(2\le N\le 10^5\),\(1\le c_v\le 10^3\)。
做法
这个东西第一次看固然是懵的,感觉就是很乱,不过细细理一理会明白它实际上在做什么。
明显我们在试图把所有点放到一个联通快里边,像是最小生成树?
注意我们这里表示的点不是所谓的结点,而是传送门。
我们本来是两个节点的每两个传送门对应连接的,它们之间也有边,分成了两块,这样显然各个传送门会不联通,我们所作的操作实际上就是把这一堆合并起来。
这下就完了,直接最小生成树做就行。
代码↓
#include <bits/stdc++.h>
using namespace std;
const int MN=1e6+116;
int father[MN], n;
int find(int x){if(father[x]!=x) father[x]=find(father[x]);return father[x];
}
void merge(int x, int y){x=find(x), y=find(y);if(x==y) return;father[x]=y; return;
}
struct Node{int pos, val;bool operator <(const Node &o)const{return val<o.val;}
}node[MN];
int G[MN][5], ans=0;
int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin>>n; for(int i=0; i<MN; ++i) father[i]=i;for(int i=1; i<=n; ++i){node[i].pos=i; cin>>node[i].val;cin>>G[i][1]>>G[i][2]>>G[i][3]>>G[i][4];merge(G[i][1],G[i][2]);merge(G[i][3],G[i][4]);}sort(node+1,node+n+1);for(int i=1; i<=n; ++i){int pos=node[i].pos;int u=find(G[pos][1]), v=find(G[pos][3]);if(u==v) continue;merge(u,v); ans+=node[i].val; }cout<<ans<<'\n';return 0;
}