zoukankan      html  css  js  c++  java
  • LCA模块+求树上两点距离最短

    1、[POJ 1330]Nearest Common Ancestors

    LCA的模版题

    因为没有告诉我们谁是根节点但是告诉我们方向了,所以我们在每次建边的时候可以记录一下,节点的父亲,如果一个节点没有父亲,那么他就是根节点。

    在倍增找LCA的时候我们首先要知道每个点的深度,bfs就好了dep数组记录深度(这道题我用的dis),一边bfs一边找每个节点的2的j次方的父亲,正确性的话,一个10进制数可以转化为一个二进制数,所以一个数就可以分解为$2^{(1.2.3.4.....)}$次方之和,所以我们才可以倍增,且一定会找到LCA。

    dfs之后开始找LCA,我们每次希望从一个深度较大的点往上跳,但是我们又很懒,不想多判断情况,所以我们人为使x节点的深度<y节点的深度。每次往上跳$2^j$次(从大到小,因为可能先跳小的再跳大的会直接被跳过),直到跳到LCA的下一个节点,然后返回他的父亲,对LCA理解的并不是那么深刻,所以可能有很多地方讲的会有错误和遗漏。

    代码,缩进太奇怪了,写完博客回小屋粘:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <queue>
     5 #include <cmath>
     6 #include <cstring>
     7 using namespace std;
     8 int t,n,x,y,root;
     9 queue<int> q;
    10 const int maxn=1e5;
    11 struct node{
    12   int to,next;
    13 }ed[maxn];
    14 int cnt,dis[maxn],f[maxn][20],fa[maxn];
    15 int head[maxn],tot;
    16 void add(int u,int to){
    17   ed[++tot].to=to;
    18   ed[tot].next=head[u];
    19   head[u]=tot;
    20 }
    21 void bfs(int s){
    22   q.push(s);
    23   dis[s]=1;
    24   while (!q.empty()){
    25     int x=q.front();q.pop();
    26     for (int i = head[x];i;i=ed[i].next){
    27       int to=ed[i].to;
    28       if (dis[to]) continue;
    29       dis[to]=dis[x]+1;
    30       f[to][0]=x;
    31       for (int j = 1;j <= cnt;j++) f[to][j]=f[f[to][j-1]][j-1];
    32       q.push(to);
    33     }
    34   }
    35 }
    36 int lca(int x,int y){
    37   if (dis[x]>dis[y]) swap(x,y);
    38   for (int i = cnt;i>=0;i--)
    39     if (dis[f[y][i]]>=dis[x])
    40       y=f[y][i];
    41   if (x==y) return x;
    42   for (int i =cnt;i >= 0;i--)
    43     if (f[x][i]!=f[y][i])
    44       x=f[x][i],y=f[y][i];
    45   return f[x][0];
    46 }
    47 int main(){
    48   scanf ("%d",&t);
    49   while (t--){
    50     memset(head,0,sizeof(head));
    51     memset(fa,0,sizeof(fa));
    52     memset(f,0,sizeof(f));
    53     memset(dis,0,sizeof(dis));
    54     tot=0;
    55     scanf ("%d",&n);
    56     cnt=log(n)/log(2)+1;
    57     for (int i = 1;i <= n-1;i++){
    58       scanf ("%d%d",&x,&y);
    59       add(x,y);fa[y]=x;
    60     }
    61     for (int i = 1;i <= n;i++) if (!fa[i]){root=i;break;}
    62     
    63     bfs(root);
    64     scanf ("%d%d",&x,&y);
    65     int ans=lca(x,y);
    66     cout<<ans<<endl;
    67   }
    68 }

    2、[HDU 2586]How far away

    LCA求树上两点的距离模版,和LCA模版没什么区别,在bfs的时候多加个数组记录一下根节点到当前节点的距离就好了,然后应用容斥的思想,不会画图就直接给结论了,a$a$-$b$的距离=根节点-$a$的距离+根节点-$b$的距离-2*(根节点-LCA(a,b))的距离,应该挺显然的。另外因为没有给出跟节点,也没给出边的方向,但其实我们在bfs的时候同时也遍历一次dfs序,选取哪个节点,按照什么顺序其实都对答案没什么影响,就随便来就好了。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 #include <queue>
     7 using namespace std;
     8 int t,n,m,x,y,w,cnt;
     9 const int maxn=1e5;
    10 int head[maxn],tot,dep[maxn],dis[maxn],f[maxn][30];
    11 struct node{
    12   int to,next,w;
    13 }ed[maxn];
    14 void add(int u,int to,int w){
    15   ed[++tot].to=to;
    16   ed[tot].w=w;
    17   ed[tot].next=head[u];
    18   head[u]=tot;
    19 }
    20 queue<int> q;
    21 void dfs(int s){
    22   q.push(s); dep[s]=1;
    23   while (!q.empty()){
    24     int x=q.front();q.pop();
    25     for(int i = head[x];i;i=ed[i].next){
    26       int to=ed[i].to;
    27       if (dep[to]) continue;
    28       dep[to]=dep[x]+1;
    29       dis[to]=dis[x]+ed[i].w;
    30       f[to][0]=x;
    31       for (int j = 1;j <= cnt;j++) f[to][j]=f[f[to][j-1]][j-1];
    32       q.push(to);
    33     }
    34   }
    35 }
    36 int lca(int x,int y){
    37   if (dep[x]>dep[y]) swap(x,y);
    38   for (int i = cnt;i >= 0;i--)
    39     if (dep[f[y][i]]>=dep[x]) y=f[y][i];
    40   if (x==y) return x;
    41   for (int i = cnt;i >= 0;i--)
    42     if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    43   return f[x][0];
    44 }
    45 int main(){
    46   scanf ("%d",&t);
    47   while (t--){
    48     memset(head,0,sizeof(head));
    49     memset(dis,0,sizeof(dis));
    50     memset(dep,0,sizeof(dep));
    51     memset(f,0,sizeof(f));
    52     tot=0;
    53     scanf ("%d%d",&n,&m);
    54     for (int i = 1;i <= n-1;i++){
    55       scanf ("%d%d%d",&x,&y,&w);
    56       add(x,y,w);add(y,x,w);
    57     }
    58     cnt=log(n)/log(2)+1;
    59     dis[1]=0;dfs(1);
    60     for (int i = 1;i <= m;i++){
    61       scanf ("%d%d",&x,&y);
    62       int ans=dis[x]+dis[y]-2*dis[lca(x,y)];
    63       cout<<ans<<endl;
    64     }
    65   }
    66   return 0;
    67 }

    3、[BZOJ 1787][AHOI 2008]紧急集合

    前两道题的变式,我们希望路径最短,就希望路径不重复(不知道对不对),然后,然后就求完了

    代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <queue>
     5 #include <cmath>
     6 #include <cstring>
     7 using namespace std;
     8 int read()
     9 {
    10     int a = 0,x = 1;
    11     char ch = getchar();
    12     while(ch > '9' || ch < '0') {
    13         if(ch == '-') x = -1;
    14         ch = getchar();
    15     }
    16     while(ch >= '0' && ch <= '9') {
    17         a = a*10 + ch-'0';
    18         ch = getchar();
    19     }
    20     return a*x;
    21 }
    22 int n,m,a,b,x,y,z;
    23 const int maxn=1e6+10;
    24 int head[maxn],dep[maxn],f[maxn][32],tot,cnt;
    25 struct node{
    26   int to,next;
    27 }ed[maxn];
    28 inline void add(int u,int to){
    29   ed[++tot].to=to;
    30   ed[tot].next=head[u];
    31   head[u]=tot;
    32 }
    33 queue<int> q;
    34 inline void bfs(int s){
    35   q.push(s);dep[s]=1;
    36   while (!q.empty()){
    37     int x=q.front();q.pop();
    38     for (register int i = head[x];i;i=ed[i].next){
    39       int to=ed[i].to;
    40       if (dep[to]) continue;
    41       dep[to]=dep[x]+1;
    42       f[to][0]=x;
    43       for (register int j = 1;j <= cnt;j++) f[to][j]=f[f[to][j-1]][j-1];
    44       q.push(to);
    45     }
    46   }
    47 }
    48 inline int lca(int x,int y){
    49   if (dep[x]>dep[y]) swap(x,y);
    50   for (int i = cnt;i >= 0;i--)
    51     if ( dep[f[y][i]]>=dep[x]) y=f[y][i];
    52   if (x==y) return x;
    53   for (register int i = cnt;i >= 0;i--)
    54     if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    55   return f[x][0];
    56 }
    57 int main(){
    58   n = read(),m = read();
    59   for (register int i = 1;i <= n-1;i++){
    60     a = read(),b = read();
    61     add(a,b);add(b,a);
    62   }
    63   cnt=30;
    64   bfs(1);
    65   for (register int i = 1;i <= m;i++){
    66     int t;
    67     x = read(),y = read(),z = read();
    68     int t1=lca(x,y);
    69     int t2=lca(x,z);
    70     int t3=lca(y,z);
    71     if (t1==t2) t=t3;
    72     if (t2==t3) t=t1;
    73     if (t1==t3) t=t2;
    74     int ans=dep[x]+dep[y]+dep[z]-dep[t1]-dep[t2]-dep[t3];
    75     printf("%d %d
    ",t,ans);
    76   }
    77   return 0;
    78 }
  • 相关阅读:
    Ext Js MVC系列二 利用Application和Viewport进行应用程序初始化和页面布局
    LINQ to Sql系列一 增,删,改
    Ext Js MVC系列一 环境搭建和MVC框架整体认识
    LINQ to Sql系列四 性能优化总结
    SQL基础回顾系列一 单表查询(select语句)
    JSON详解
    公用类库(4) 缓存操作类CacheUtil
    架构设计考虑的问题(出自代码大全II)
    .net自动更新组件Ant
    .net socket在win2008下的吞吐性能报告
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13704935.html
Copyright © 2011-2022 走看看