题目链接  CCPC2016 Changchun Problem E

题意  给定一个$n$个点$n$条边的无向图,现在从某一点$s$出发,每个点都经过一遍,最后在$t$点停止,经过的边数为$l$

    求字典序最小的三元组$(l, s, t)$

设环的长度为$c$,

当$s$和$t$在同一棵子树上的时候,$s$到$t$的路径上的边和环上的边只要走一次,其他边都要走两次,那么答案为$2n - c - len$

$len$为$s$到$t$的路径的长度;

当$s$和$t$不在同一棵子树上的时候,设$s$走到环上的第一个点为$u$,$t$走到环的第一个点为$v$。

那么这个时候考虑每条边走过的次数。

对于不在环上的边,从$s$到$u$,从$v$到$t$的路径只要走一次,其余的边都要走两次。

对于在环上的边,从$u$到$v$的路径只要走一次,其余的部分都要走两次,但是有一条边不用经过(一次都不用走)

那么答案为$2n - 2 - len(s, u) - len(u, v) - len(v, t)$;

对于第一种情况,我们对环上每棵树都求一条字典序最小的直径然后更新答案即可。

对于第二种情况,我们需要最大化$len(s, u) + len(u, v) + len(v, t)$的值。

考虑每个环上的点,显然$s$和$t$的最佳选择都是从这个点往里走可以走到的最深的点。

设环上的点依次排列为:$a_{1}, a_{2}, a_{3}, ......, a_{cnt}$。

设每个环上的点往子树方向走能走到的最深的深度为$c_{1}, c_{2}, c_{3}, ......, c_{cnt}$

倍长a数组和c数组,对于每个位置$i(cnt < i <= 2 * cnt)$,找到一个最佳的点$j(i - cnt + 1 <= j <= i - 1)$。

使得$i - j + c[j] + c[i] = i + c[i] + (c[j] - j)$的值最大。

那么用单调队列维护$c[j] - j$的最大值即可。我为了方便偷懒用了ST表。

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. #define rep(i, a, b) for (int i(a); i <= (b); ++i)
  6. #define dec(i, a, b) for (int i(a); i >= (b); --i)
  7. #define fi first
  8. #define se second
  9. #define MP make_pair
  10.  
  11. typedef long long LL;
  12. typedef pair <int, int> PII;
  13.  
  14. const int N = 1e5 + 10;
  15.  
  16. struct node{
  17. int x, y;
  18. } b[N << 1];
  19.  
  20. node f[N << 1][20];
  21.  
  22. int T;
  23. int n, cnt;
  24. int a[N], isroot[N], father[N], vis[N];
  25. int len, l, r;
  26. int lg[N << 1];
  27. int m;
  28. int ca = 0;
  29. vector <int> v[N];
  30. pair <int, PII> ans;
  31. PII c[N];
  32.  
  33. int get_circle(int x){
  34. vis[x] = 1;
  35. for (auto u : v[x]){
  36. if (u == father[x]) continue;
  37. father[u] = x;
  38. if (vis[u]){
  39. cnt = 0;
  40. int w = x;
  41. while (w ^ u){
  42. a[++cnt] = w;
  43. isroot[w] = cnt;
  44. w = father[w];
  45. }
  46.  
  47. a[++cnt] = u;
  48. isroot[u] = cnt;
  49. return 1;
  50. }
  51. if (get_circle(u)) return 1;
  52. }
  53.  
  54. return 0;
  55. }
  56.  
  57. inline node mx(const node &a, const node &b){
  58. if (a.x == b.x){
  59. if (a.y < b.y) return a;
  60. else return b;
  61. }
  62.  
  63. if (a.x > b.x) return a; else return b;
  64. }
  65.  
  66. void dfs(int x, int fa, int dep){
  67. if ((dep > len) || (dep == len && x < l)){
  68. len = dep;
  69. l = x;
  70. }
  71.  
  72. for (auto u : v[x]){
  73. if (u == fa || isroot[u]) continue;
  74. dfs(u, x, dep + 1);
  75. }
  76. }
  77.  
  78. void dfs2(int x, int fa, int dep, int extra){
  79. if ((dep > len) || (dep == len && x < r)){
  80. len = dep;
  81. r = x;
  82. }
  83.  
  84. for (auto u : v[x]) if ((u != fa) && (!isroot[u] || u == extra)){
  85. dfs2(u, x, dep + 1, extra);
  86. }
  87. }
  88.  
  89. inline node solve(int l, int r){
  90. int k = lg[r - l + 1];
  91. return mx(f[l][k], f[r - (1 << k) + 1][k]);
  92. }
  93.  
  94. int main(){
  95.  
  96. lg[1] = 0;
  97. rep(i, 2, 2e5) lg[i] = lg[i >> 1] + 1;
  98.  
  99. scanf("%d", &T);
  100. while (T--){
  101. scanf("%d", &n);
  102. if (n == 2) while (1);
  103. rep(i, 0, n + 1){
  104. v[i].clear();
  105. isroot[i] = 0;
  106. father[i] = 0;
  107. vis[i] = 0;
  108. }
  109.  
  110. cnt = 0;
  111. rep(i, 1, n){
  112. int x, y;
  113. scanf("%d%d", &x, &y);
  114. v[x].push_back(y);
  115. v[y].push_back(x);
  116. }
  117.  
  118. father[1] = 0;
  119. get_circle(1);
  120.  
  121. memset(c, -1, sizeof c);
  122. ans = MP(1e9, MP(-1, -1));
  123. rep(i, 1, cnt){
  124. len = -1;
  125. l = -1;
  126. r = -1;
  127. dfs(a[i], 0, 0);
  128.  
  129. c[i] = MP(len, l);
  130. len = -1;
  131. dfs2(l, 0, 0, a[i]);
  132. if (l > r) swap(l, r);
  133. ans = min(ans, MP(2 * n - len - cnt, MP(l, r)));
  134. }
  135.  
  136. rep(i, 1, cnt){
  137. b[i] = {c[i].fi - i + 1, c[i].se};
  138. b[i + cnt] = {c[i].fi - (i - 1 + cnt), c[i].se};
  139. }
  140.  
  141. m = cnt << 1;
  142. memset(f, 0, sizeof f);
  143.  
  144. rep(i, 1, m) f[i][0] = b[i];
  145. rep(j, 1, 18){
  146. rep(i, 1, m){
  147. if ((i + (1 << j) - 1) <= m) f[i][j] = mx(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
  148. }
  149. }
  150.  
  151. rep(i, cnt + 1, m){
  152. node now = solve(i - cnt + 1, i - 1);
  153. int ll = now.y, rr = c[i - cnt].se;
  154. if (ll > rr) swap(ll, rr);
  155. int ret = c[i - cnt].fi + i - 1 + (now.x);
  156. ans = min(ans, MP(2 * n - 2 - ret , MP(ll, rr) ) );
  157. }
  158. printf("Case #%d: %d %d %d\n", ++ca, ans.fi, ans.se.fi, ans.se.se);
  159. }
  160.  
  161. return 0;
  162.  
  163. }

HDU 5915 The Fastest Runner Ms. Zhang (CCPC2016 长春 E题,分类讨论 + 求字典序最小的直径 + 数据结构寻找最小值)的更多相关文章

  1. HDU 4423 Simple Function(数学题,2012长春D题)

    Simple Function Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  2. hdu 2191 珍惜现在,感恩生活 多重背包入门题

    背包九讲下载CSDN 背包九讲内容 多重背包: hdu 2191 珍惜现在,感恩生活 多重背包入门题 使用将多重背包转化为完全背包与01背包求解: 对于w*num>= V这时就是完全背包,完全背 ...

  3. HDU 2080 夹角有多大II (数学) atan(y/x)分类求角度

    夹角有多大II Problem Description 这次xhd面临的问题是这样的:在一个平面内有两个点,求两个点分别和原点的连线的夹角的大小.注:夹角的范围[0,180],两个点不会在圆心出现. ...

  4. HDU 5203 Rikka with wood sticks 分类讨论

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5203 bc(chinese):http://bestcoder.hdu.edu.cn/con ...

  5. HDU 1533:Going Home(KM算法求二分图最小权匹配)

    http://acm.hdu.edu.cn/showproblem.php?pid=1533 Going Home Problem Description   On a grid map there ...

  6. HDU 6627 equation (分类讨论)

    2019 杭电多校 5 1004 题目链接:HDU 6627 比赛链接:2019 Multi-University Training Contest 5 Problem Description You ...

  7. HDU 6665 Calabash and Landlord (分类讨论)

    2019 杭电多校 8 1009 题目链接:HDU 6665 比赛链接:2019 Multi-University Training Contest 8 Problem Description Cal ...

  8. hdu 1465:不容易系列之一(递推入门题)

    不容易系列之一 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  9. HDU 2504 又见GCD(最大公约数与最小公倍数变形题)

    又见GCD Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

随机推荐

  1. python2.7写入文件时指定编码为utf-8

    python3.0可以这样写 f = open('ufile.log', 'w', 'utf-8')   但在python2.7中open()没有编码参数,如上那样写会报错,可以使用如下模块 impo ...

  2. appium 多个设备同时执行

    测试需要同时在多个android设备上运行,就需要启动多个appium 使用adb命令获取udid,命令:adb get-serialno 使用的是testng测试框架,代码使用java编写 第一台, ...

  3. == 与 equals 之区别

    "=="和equals方法究竟有什么区别? (单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚) ==操作符专门用来比较两个变量的值 ...

  4. Oz 创建CentOS7镜像

    参考链接: https://github.com/clalancette/oz/wiki/Oz-template-description-language https://github.com/cla ...

  5. 【多线程学习(1)】创建java多线程

    1)java多线程的创建方式有三种: 1.继承Thread类 2.实现Runnable接口 3.实现Callable接口 第一种: //继承Thread类 class ExtendsThread ex ...

  6. C++ 虚继承内存分配

    我们知道,虚继承的基类在类的层次结构中只可能出现一个实例.虚基类在类的层次结构中的位置是不能固定的,因为继承了虚基类的类可能会再次被其他类多继承. 比如class A: virtual T{} 这时T ...

  7. Win10 Ubuntu18.04 编译安装 nignx

    nginx 下载页 http://nginx.org/en/download.html wget http://nginx.org/download/nginx-1.14.0.tar.gz //安装依 ...

  8. 【Python】- 第一行跟第二行的写法

    第一行:目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python:告诉操作系统执行这个脚本的时候,调用/usr/bin下的python解释器: ...

  9. 【DNS】DNS的几个基本概念

    一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点,而这也已经成为了习惯. 根域服 ...

  10. macOS Sierra下如何打开任何来源(10.12系统)

    转载声明:本站文章无特别说明皆为原创,转载请注明:史蒂芬周的博客, 一定有很多朋友和小子一样,迫不及待的升级到了macOS Sierra,随之而来的是第三方应用都无法打开了,提示无法打开或者扔进废纸篓 ...