[省选联考 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; }
 
 
   |