【旅行】

Description



【題解】

 一道lca水題

隨便畫畫圖就可以看出ABC之間的關係只有三種

1.三個節點有共同的共祖先  

2.兩個節點的公共祖先與另一個節點的公共祖先相同,且這個公共祖先是那兩個節點公共祖先的祖先

3.兩個節點的公共祖先與另一個節點的公共祖先相同,且這個這兩個節點的公共祖先時兩個節點其中一個(一條鏈的情況)


圖比較醜隨便看看

因此我們只需要對於三個點兩兩找lca 然後判斷出是那種情況

剩下的就比較簡單了 參照代碼查看集合點和距離的做法

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>
using namespace std;
int i,j,k,l,m,n,x,y,z,fa,fb,fc,q,num;
int f[200005][22],d[200005],first[200005];
struct info
  {
  	int ar,next;
  }tree[400005];
void add(int x,int y) {tree[++num]={y,first[x]};first[x]=num;}
void dfs(int u,int fat)
  {
  	int i,v;
  	for (i=first[u];i;i=tree[i].next)
  	  {
  	  	v=tree[i].ar;
  	  	if (v==fat) continue;
  	  	d[v]=d[u]+1;f[v][0]=u;
  	  	dfs(v,u);
	  }
  }
int lca(int u,int v)
  {
  	int i;
  	if (d[v]>d[u]) swap(u,v);
  	for (;d[u]>d[v];)
  	  {
  	  	for (i=0;d[f[u][i]]>=d[v];i++);i--;
  	  	u=f[u][i];
	  }
	for (;u!=v;)
	  {
	  	for (i=1;f[u][i]!=f[v][i];i++);i--;
	  	u=f[u][i];v=f[v][i];
	  }
	return(u);
  }
int main()
  {
  	scanf("%d%d",&n,&m);
  	for (i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); 
  	
	  f[1][0]=1;d[1]=1;
	  dfs(1,-1);
  	for (i=1;i<=20;i++)
  	  for (j=1;j<=n;j++) 
  	    f[j][i]=f[f[j][i-1]][i-1];
  	for (i=1;i<=m;i++)
  	  {
  	  	scanf("%d%d%d",&x,&y,&z);
  	  	fa=lca(x,y);fb=lca(y,z);fc=lca(x,z);
  	  	if (fa==fb&&fb==fc)
  	  	  {
  	  	  	q=d[x]+d[y]+d[z]-3*d[fa];
  	  	  	printf("%d %d\n",fa,q);
  	  	  	continue;
		  }
		if (fa==fc) {swap(x,y);}
		if (fb==fc) {swap(y,z);}
		fa=lca(x,y);fb=lca(y,z);fc=lca(x,z);
		if (fa==fb)
		  {
		  	if (fc==z||fc==x)
		  	  {
		  	  	if (fc==z){q=d[x]+d[y]-2*d[fa];printf("%d %d\n",z,q);continue;}
				if (fc==x){q=d[z]+d[y]-2*d[fa];printf("%d %d\n",x,q);continue;}
				continue;
			  }
			else
			{
			 q=d[x]+d[z]-2*d[fc]+d[fc]+d[y]-2*d[lca(fc,y)];
			 printf("%d %d\n",fc,q);
		    }
		  }
	  }
  }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章