Luogu 2573 [SCOI2012]滑雪
BZOJ 2753
首先可以按照题目要求的把所有的有向边建出来,然后进去广搜就可以求出第一问的解,然后考虑如何求解第二问,我们把所有搜到的边按照到达的点的高度位第一关键字,边的长度为第二关键字排序之后跑$kruskal$,这样子得到的最小生成树权值就是第二问所求的最大值。
考虑一下这样子为什么正确,首先“时间胶囊”的返回形式让答案一定是一棵生成树的权值,但是直接跑最小生成树可能会造成有一些点不能走到的情况,所以我们搜出所有的可能能到达的点,然后按照点的海拔高度先排序之后就一定能保证所有点都能走到,这样子求出来的生成树也一定是最小代价的。
时间复杂度$O(mlogm)$。
Code:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long ll; const int N = 1e5 + 5; const int M = 1e6 + 5; int n, m, num = 0, tot = 0, head[N], edgeNum = 0, ufs[N]; ll h[N]; bool vis[N]; struct Edge { int to, nxt; ll val; } e[M << 1]; inline void add(int from, int to, ll val) { e[++tot].to = to; e[tot].val = val; e[tot].nxt = head[from]; head[from] = tot; } struct Pathway { int u, v; ll val; friend bool operator < (const Pathway &x, const Pathway &y) { if(h[x.v] != h[y.v]) return h[x.v] > h[y.v]; else return x.val < y.val; } } pat[M << 1]; template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9'|| ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void init() { for(int i = 1; i <= n; i++) ufs[i] = i; } int find(int x) { return ufs[x] == x ? x : ufs[x] = find(ufs[x]); } queue <int> Q; void bfs() { Q.push(1); vis[1] = 1; num = 1; for(; !Q.empty(); ) { int x = Q.front(); Q.pop(); for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; pat[++edgeNum] = (Pathway) {x, y, e[i].val}; if(!vis[y]) { vis[y] = 1; ++num; Q.push(y); } } } } inline ll kruskal() { init(); sort(pat + 1, pat + 1 + edgeNum); ll res = 0LL; for(int cnt = 0, i = 1; i <= edgeNum; i++) { int u = find(pat[i].u), v = find(pat[i].v); if(u == v) continue; ufs[u] = v; ++cnt; res += pat[i].val; if(cnt >= num - 1) break; } return res; } int main() { // freopen("3.in", "r", stdin); read(n), read(m); for(int i = 1; i <= n; i++) read(h[i]); for(int i = 1; i <= m; i++) { int x, y; ll v; read(x), read(y), read(v); if(h[x] >= h[y]) add(x, y, v); if(h[x] <= h[y]) add(y, x, v); } bfs(); printf("%d %lld\n", num, kruskal()); return 0; }