本质上还是树形dp。建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则)。原本是对于圆上的点进行 \(n^{2}\) 的匹配,果断超时。但没有发现 \(n ^ {2}\) 的dp明显是一个可以单调队列优化的dp。所以在遇上难解决的问题的时候,一定要融会贯通地思考。有一个细节:将圆复制一下可以去掉 \(max\)造成的影响,dp就十分方便了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define maxn 500000
  4. int n, m, N, timer, ans;
  5. int fa[maxn], dfn[maxn], low[maxn];
  6. int f[maxn][], id[maxn], S[maxn];
  7. int tmp[maxn], q[maxn];
  8. int F[maxn][], SS[maxn];
  9.  
  10. struct edge
  11. {
  12. int cnp, head[maxn], to[maxn], last[maxn], w[maxn];
  13. edge() { cnp = ; }
  14. void add(int u, int v, int ww)
  15. {
  16. to[cnp] = v, last[cnp] = head[u], w[cnp] = ww, head[u] = cnp ++;
  17. to[cnp] = u, last[cnp] = head[v], w[cnp] = ww, head[v] = cnp ++;
  18. }
  19. }E1, E2;
  20.  
  21. int read()
  22. {
  23. int x = , k = ;
  24. char c;
  25. c = getchar();
  26. while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
  27. while(c >= '' && c <= '') x = x * + c - '', c = getchar();
  28. return x * k;
  29. }
  30.  
  31. void Solve(int u, int v)
  32. {
  33. ++ N; int ID = , pre = ;
  34. for(int i = v; i != fa[u]; i = fa[i])
  35. S[i] = pre ++, id[i] = ++ ID;
  36. S[N] = S[u], S[u] = ;
  37. for(int i = v; i != fa[u]; i = fa[i])
  38. E2.add(N, i, min(S[i], S[N] - S[i]));
  39. }
  40.  
  41. void Tarjan(int u)
  42. {
  43. dfn[u] = low[u] = ++ timer;
  44. for(int i = E1.head[u]; i; i = E1.last[i])
  45. {
  46. int v = E1.to[i];
  47. if(v == fa[u]) continue;
  48. if(!dfn[v])
  49. {
  50. fa[v] = u; Tarjan(v);
  51. low[u] = min(low[u], low[v]);
  52. }
  53. else low[u] = min(low[u], dfn[v]);
  54. if(low[v] > dfn[u]) E2.add(u, v, );
  55. }
  56. for(int i = E1.head[u]; i; i = E1.last[i])
  57. {
  58. int v = E1.to[i];
  59. if(dfn[u] < dfn[v] && fa[v] != u) Solve(u, v);
  60. }
  61. }
  62.  
  63. void update(int u, int w)
  64. {
  65. if(w <= f[u][]) return;
  66. if(w < f[u][]) f[u][] = w;
  67. else f[u][] = f[u][], f[u][] = w;
  68. }
  69.  
  70. bool cmp(int a, int b) { return id[a] < id[b]; }
  71.  
  72. int Work(int u)
  73. {
  74. int head = , tail = , cnt = , ans = , len = ;
  75. for(int i = E2.head[u]; i; i = E2.last[i])
  76. tmp[++ cnt] = f[E2.to[i]][], len ++;
  77. for(int i = ; i <= len; ++ i)
  78. tmp[++ cnt] = tmp[i];
  79. q[head] = ;
  80. for(int i = ; i <= cnt; ++ i)
  81. {
  82. while(head < tail && i - q[head] > len / ) ++ head;
  83. ans = max(ans, tmp[i] + tmp[q[head]] + i - q[head]);
  84. while(head <= tail && tmp[i] - i > tmp[q[tail]] - q[tail] ) -- tail;
  85. q[++ tail] = i;
  86. }
  87. return ans;
  88. }
  89.  
  90. void dfs(int u, int ff)
  91. {
  92. for(int i = E2.head[u]; i; i = E2.last[i])
  93. {
  94. int v = E2.to[i];
  95. if(v == ff) continue; else dfs(v, u);
  96. update(u, f[v][] + E2.w[i]);
  97. }
  98. if(u <= n) ans = max(ans, f[u][] + f[u][]);
  99. else ans = max(ans, Work(u));
  100. }
  101.  
  102. int main()
  103. {
  104. N = n = read(), m = read();
  105. for(int i = ; i <= m; i ++)
  106. {
  107. int tot = read(), u, pre;
  108. for(int j = ; j <= tot; j ++)
  109. {
  110. u = read(); if(j == ) { pre = u; continue; }
  111. E1.add(u, pre, ); pre = u;
  112. }
  113. }
  114. Tarjan();
  115. dfs(, );
  116. printf("%d\n", ans);
  117. return ;
  118. }

【题解】SHOI2008仙人掌图的更多相关文章

  1. [SHOI2008]仙人掌图

    [SHOI2008]仙人掌图 LG传送门 还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理. 题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度. 按照套路,先考虑求树的直径我 ...

  2. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

  3. BZOJ1023:[SHOI2008]仙人掌图——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1023 Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple ...

  4. SHOI2008仙人掌图(tarjan+dp)

    Solution 好题啊没的说. 本题需要求出仙人掌的直径,但仙人掌是一个带有简单环的一张图无法直接用树形dp求解,但它有一个好东西就是没有类似环套环的东西,所以我们在处理时就方便了一些. 思路:ta ...

  5. [SHOI2008]仙人掌图 II——树形dp与环形处理

    题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...

  6. BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列

    传送门 求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断. 沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响. 设环长为\(cir\),在\(df ...

  7. Luogu 4244 [SHOI2008]仙人掌图

    BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...

  8. P4244 [SHOI2008]仙人掌图 II

    传送门 仙人掌直径,以前好像模拟赛的时候做到过一道基环树的直径,打了个很麻烦的然而还错了--今天才发现那就是这个的弱化版啊-- 如果是树的话用普通的dp即可,记\(f[u]\)表示\(u\)往下最长能 ...

  9. 洛谷P4244 [SHOI2008]仙人掌图 II

    传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...

随机推荐

  1. 解决url传递过程中加号变空格的问题

    url传递过程中加号变空格 在接收url参数的过程中,会发现如果参数中存在‘+’号,接收后会变成空格. 如11+22接收后变成11 22. 要解决这个问题,需要将加号替换为%2B进行传递. 如11%2 ...

  2. Laravel系列之CMS系统学习 — 角色、权限配置【2】

    一.RBAC分析 基于角色的权限访问控制(Role-Based Access Control),这里存在这么几个玩意儿:角色.权限,用户 表:roles.permissions.role_has_pe ...

  3. ubuntu 18 lnmp

    1安装Nginx sudo apt-get install nginx 2安装PHP sudo apt- php7.-fpm 3安装mysql sudo apt-get install mysql 启 ...

  4. LINUX SSH 建立密钥对

    配置私钥和公钥 先检查一下服务器的ssh配置文件 /etc/ssh/sshd_config RSAAuthentication yes # 启用 RSA 认证 默认为 yes PubkeyAuthen ...

  5. MetInfo最新网站漏洞如何修复以及网站安全防护

    metinfo漏洞于2018年10月20号被爆出存在sql注入漏洞,可以直接拿到网站管理员的权限,网站漏洞影响范围较广,包括目前最新的metinfo版本都会受到该漏洞的攻击,该metinfo漏洞产生的 ...

  6. crest value &minimum

    public class paixu { public static void main(String[] args) { double temp; double num[]={5.1, 7.12, ...

  7. java入门---基础语法&基础常识&编码规范&命名规范

        一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一条狗是一个对 ...

  8. Java中的IO流体系

    Java为我们提供了多种多样的IO流,我们可以根据不同的功能及性能要求挑选合适的IO流,如图10-7所示,为Java中IO流类的体系. 注:这里只列出常用的类,详情可以参考JDK API文档.粗体标注 ...

  9. 为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?

    默认情况下,block里面的变量,拷贝进去的是变量的值,而不是指向变量的内存的指针.使用__block修饰后的变量,拷贝到block里面的就是指向变量的指针,所以我们就可以修改变量的值.

  10. 【连载】Bootstrap开发漂亮的前端界面之自定义右键菜单

    连载: 1<教你用Bootstrap开发漂亮的前端界面> 2.<Bootstrap开发漂亮的前端界面之实现原理> 网页中的自定义右键菜单越来越普遍,自定义右键菜单可以增强用户体 ...