[省选联考 2020 B 卷] 丁香之路 - 洛谷
感觉题目比较神仙。
首先画画图,第一个很明显的就是如果每条需要走的边的点都是单调的,那么答案肯定就是直接按照最近的点连接。根据这样的情况我们发现这个就是一条链。
之后考虑一个点度数比较大的菊花的形式,菊花就会导致我们被迫走回头路,这个东西不好考虑。鉴于我们可以随意加边,我们不妨将回头路看成一条新的边,这样我们最终的答案就是每条边都只经过了一次。
每条边只经过一次的路径 $\to $ 欧拉路径。
对于欧拉路径的情况我们只需要保证每个节点的度数即可。
对于欧拉路径我们可以让 $S \to T$ 进行连边,这样我们可以不用考虑起始点和结束点究竟连接的是那个点,直接变成欧拉回路。
之后我们考虑对于奇数点进行连边。
但是可能会出现若干个环的情况,我们还是需要考虑图的连通性。直观的想法就是考虑将不同连通块之间连边之后最小生成树。
显然我们贪心考虑相邻连边即可, 为了保证欧拉回路所以最小生成树上的边肯定会经过两次。
或者说如果要遍历一遍最小生成树而且回到起点,那么每条边肯定会经过两次。
回到起点的原因就是我们将起点和终点连边,他们肯定在一个连通块内。
发现最小生成树上的边是不优的,所以我们要让连通块要尽量连通,对于 $u \to v$ 我们肯定可以拆成 $u \to u + 1 \to u + 2 \to \cdots \to v$ 这个本质是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #include <bits/stdc++.h> using namespace std; namespace Legendgod { namespace Read {
#ifdef Fread const int Siz = (1 << 21) + 5; char *iS, *iT, buf[Siz]; #define gc() ( iS == iT ? (iT = (iS = buf) + fread(buf, 1, Siz, stdin), iS == iT ? EOF : *iS ++) : *iS ++ ) #define getchar gc #endif template <typename T> void r1(T &x) { x = 0; char c(getchar()); int f(1); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); x *= f; } template <typename T, typename...Args> void r1(T &x, Args&...arg) { r1(x), r1(arg...); } #undef getchar }
using namespace Read;
const int maxn = 2e5 + 5; int n, m, S, deg[maxn], fa[maxn], nf[maxn];
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); } void merge(int u,int v) { u = getfa(u), v = getfa(v); if(u == v) return ; fa[u] = v; }
typedef long long int64; int64 sum(0), ans;
struct Node { int u, v, w; int operator < (const Node &z) const { return w < z.w; } }e[maxn]; int etot(0);
signed main() { int i, j; r1(n, m, S); for(i = 1; i <= n; ++ i) fa[i] = i; for(i = 1; i <= m; ++ i) { int u, v; r1(u, v), ++ deg[u], ++ deg[v]; sum += abs(u - v); merge(u, v); }
for(i = 1; i <= n; ++ i) nf[i] = getfa(i); for(i = 1; i <= n; ++ i) { ans = sum; for(j = 1; j <= n; ++ j) fa[j] = nf[j]; ++ deg[i], ++ deg[S]; int pre(0); for(j = 1; j <= n; ++ j) if(deg[j] & 1) { if(!pre) pre = j; else { ans += j - pre; for(int k = pre; k < j; ++ k) merge(k, k + 1); pre = 0; } } pre = etot = 0; for(j = 1; j <= n; ++ j) if(deg[j]) { if(pre && getfa(j) != getfa(pre)) { e[++ etot] = { pre, j, j - pre }; } pre = j; }
sort(e + 1, e + etot + 1); for(j = 1; j <= etot; ++ j) { auto [u, v, w] = e[j]; if(getfa(u) != getfa(v)) ans += w * 2, merge(u, v); } -- deg[i], -- deg[S]; printf("%lld%c", ans, " \n"[i == n]); } return 0; }
}
signed main() { return Legendgod::main(), 0; }
|