• Codeforces Round #425 (Div. 2) D 题解


    题目链接

    题目描述

    有一棵具有 n 个节点的树,在这棵树上将有 m 次询问。
    每次询问将给出三个点:a,b,c,你需要在这三个点中选出两个点作为起点,一个点作为终点,由此得到两条路径,且两条路径不能完全重合
    例如:你可以选择 a,c 作为起点,b 作为终点,从而得到路径 (a,b),(b,c)。
    求选出的两条路径能够得到的最多公共节点数。

    解题思路

    我们考虑对于一个树,在选取的三个节点中,求出两两对应的三个LCA,此时我们可以找到每个 lca 和终点的距离再比较距离的大小就可以得到结果。其实如果我们仔细想一下,我们只要找到深度最深的 lca 再比较它到每个点的距离就可以了。因为最深的 lca 点一定是会经过两条路径的点。这里给个图帮助大家理解。

    这里求 lca 的方法有很多,倍增方法可以,树链剖分方法也可以,我个人用的是树链剖分的方法。

    代码示例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. const int maxn=2010000;
    8. int n,m,s;
    9. int cnt;
    10. int tot;
    11. int head[maxn];
    12. int dep[maxn];
    13. int fa[maxn];
    14. int top[maxn];
    15. int siz[maxn];
    16. int son[maxn];
    17. int dfn[maxn];
    18. struct edge{
    19. int to;
    20. int from;
    21. int nxt;
    22. }e[2*maxn];
    23. void add(int x,int y){
    24. tot++;
    25. e[tot].to=y;
    26. e[tot].from=x;
    27. e[tot].nxt=head[x];
    28. head[x]=tot;
    29. }
    30. void dfs_1(int x,int f){
    31. dep[x]=dep[f]+1;
    32. fa[x]=f;
    33. siz[x]=1;
    34. int maxson=-1;
    35. for(int i=head[x];i;i=e[i].nxt){
    36. int y=e[i].to;
    37. if(y==f) continue;
    38. dfs_1(y,x);
    39. siz[x]+=siz[y];
    40. if(siz[y]>maxson){
    41. son[x]=y;
    42. maxson=siz[y];
    43. }
    44. }
    45. }
    46. void dfs_2(int x,int topf){
    47. dfn[x]=++cnt;
    48. top[x]=topf;
    49. if(!son[x]) return;
    50. dfs_2(son[x],topf);
    51. for(int i=head[x];i;i=e[i].nxt){
    52. int y=e[i].to;
    53. if(y==fa[x]||y==son[x]) continue;
    54. dfs_2(y,y);
    55. }
    56. }
    57. int get_lca(int x,int y){
    58. while(top[x]!=top[y]){
    59. if(dep[top[x]]swap(x,y);
    60. x=fa[top[x]];
    61. }
    62. if(dep[x]return x;
    63. else return y;
    64. }
    65. int get_dis(int x,int y){
    66. int ans=0;
    67. while(top[x]!=top[y]){
    68. if(dep[top[x]]swap(x,y);
    69. ans+=dep[x]-dep[top[x]]+1;
    70. x=fa[top[x]];
    71. }
    72. if(dep[x]1;
    73. else ans+=dep[x]-dep[y]+1;
    74. return ans;
    75. }
    76. int main(){
    77. cin>>n>>m;
    78. int x,y,z;
    79. int lca;
    80. for(int i=2;i<=n;i++){
    81. cin>>x;
    82. add(x,i);
    83. add(i,x);
    84. }
    85. dfs_1(1,0);
    86. dfs_2(1,1);
    87. while(m--){
    88. cin>>x>>y>>z;
    89. int lca_1=get_lca(x,y);
    90. int lca_2=get_lca(x,z);
    91. int lca_3=get_lca(y,z);
    92. if(dep[lca_2]>dep[lca_1]) lca_1=lca_2;
    93. if(dep[lca_3]>dep[lca_1]) lca_1=lca_3;
    94. cout<<max(get_dis(lca_1,x),max(get_dis(lca_1,y),get_dis(lca_1,z)))<
    95. }
    96. return 0;
    97. }
  • 相关阅读:
    【Leetcode】171.Excel 表列序号
    使用 Git 工具进行项目管理
    测试左移和右移怎么做,这篇文章写的太详细了
    二叉树的最近公共祖先LCA
    高阶数据结构—— 哈希
    TCO-PEG-FITC 荧光素-聚乙二醇-反式环辛烯 TCO-PEG-荧光素
    Gvim显示行号、最大化、字号、主题等常用配置修改
    kafka主题脚本常用指令
    flume异常关闭文件修复方法
    前端跨页面通信,你知道哪些方法?
  • 原文地址:https://blog.csdn.net/haobowen/article/details/126463673