【LCA】洛谷P3398 仓鼠找sugar

Link


题目

【LCA】洛谷P3398 仓鼠找sugar_第1张图片
【LCA】洛谷P3398 仓鼠找sugar_第2张图片


思路

树形结构求两点间的最短路可用LCA,然后我们可以发现,两条路如果相交的话其中一条路的两点的LCA必定是在另一条路上的。

Code

#include
#include
using namespace std;
int n,q,t;
int l[500001],jump[500001],Deep[500001],father[500001][101];
struct asdf{
 int to,next;
} A[1000001];
void read(){  //读入
 int x,y;
 scanf("%d%d", &n, &q);
 for(int i = 1; i < n; ++i){
  scanf("%d%d", &x, &y);
  A[++t] = (asdf){y,l[x]}; l[x] = t;  //邻接表存储
  A[++t] = (asdf){x,l[y]}; l[y] = t;
 }
 int k = 1;
 jump[1] = 1;  //预处理jump。jump[i]为在深度为i的时候可以跳2^(i-1)的步数
 for(int i = 2; i <= n; ++i){
  jump[i] = jump[i-1];
  if(i / k == 2){
   k*=2;
   ++jump[i];
  }
 }
}
void dfs(int now,int fu){  //当前点和父亲//dfs求某节点跳2^k步是哪个节点
 father[now][0] = fu;  //跳2^0步 
 Deep[now] = Deep[fu] + 1;  //深度统计
 for(int i = 1; i <= jump[Deep[now]]; ++i)
   father[now][i] = father[father[now][i-1]][i-1]; 
    //从当前点跳2^i步=跳了2^(i-1)步的点后再跳2^(i-1)步
 for(int i = l[now]; i; i = A[i].next) 
   if(Deep[A[i].to] == 0) dfs(A[i].to,now);
}
int lca(int x,int y){
 if(Deep[x]>Deep[y]){  //让y的深度大于x的深度
        int l = x;
  x = y;
  y = l; 
 } 
 while(Deep[x] != Deep[y]) y = father[y][jump[Deep[y] - Deep[x]] - 1];
 //让x和y跳到同一高度  //y跳的时候就有倍增跳跃
 if(x == y) return x; 
 for(int i = jump[Deep[x]]-1; i>=0; --i)  //跳跃
     if(father[x][i] != father[y][i]){  //如果父亲不一样就跳过去
       //如果父亲一样可能会跳过头  //所以我们的目标是最近公共祖先的子节点
      x = father[x][i];
      y = father[y][i]; 
     }
 return father[x][0];  //返回
}
int vis(int xx,int yy){
 int lll = lca(xx,yy);
  return Deep[xx]-Deep[lll] + Deep[yy]-Deep[lll];
}
int main(){
 read();
 dfs(1,0);  //先dfs 
 for(int i = 1; i <= q; ++i){
  int a,b,c,d,xx,yy;
  scanf("%d%d%d%d",&a,&b,&c,&d);
  xx = lca(a,b); yy = lca(c,d);
  if(vis(a, yy)+vis(b, yy)==vis(a, b) || vis(c, xx)+vis(d, xx)==vis(c, d)) printf("Y\n");  //判断一下是否相交。 
  else printf("N\n"); 
 }
}

你可能感兴趣的:(图论)