转换成抽象模型,就是要求一棵树(N个点,有N-1条边表示这个图是棵树)中某一点满足给定三点a,b,c到某一点的距离和最小。那么我们想到最近公共祖先的定义,推出只有集合点在LCA(a,b)、LCA(a,c)、LCA(b,c)中,才能保证距离和最近。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-9 # define MOD 100000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=500005; //Code begin... struct Edge{int to, next;}edge[N<<1]; int head[N], tot, fa[N][20], deg[N]; queue<int>que; void add_edge(int u, int v){edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++;} void init(){tot=0; mem(head,-1);} void BFS(int root){ deg[root]=0; fa[root][0]=root; que.push(root); while (!que.empty()) { int tmp=que.front(); que.pop(); FO(i,1,20) fa[tmp][i]=fa[fa[tmp][i-1]][i-1]; for (int i=head[tmp]; i!=-1; i=edge[i].next) { int v=edge[i].to; if (v==fa[tmp][0]) continue; deg[v]=deg[tmp]+1; fa[v][0]=tmp; que.push(v); } } } int LCA(int u, int v){ if (deg[u]>deg[v]) swap(u,v); int hu=deg[u], hv=deg[v], tu=u, tv=v; for (int det=hv-hu, i=0; det; det>>=1, i++) if (det&1) tv=fa[tv][i]; if (tu==tv) return tu; for (int i=19; i>=0; --i) { if (fa[tu][i]==fa[tv][i]) continue; tu=fa[tu][i]; tv=fa[tv][i]; } return fa[tu][0]; } int main () { int n, m, u, v, w, x, y, tmp, p; init(); n=Scan(); m=Scan(); FO(i,1,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u); BFS(1); while (m--) { int ans=INF; scanf("%d%d%d",&u,&v,&w); x=LCA(u,v); tmp=deg[u]+deg[v]-2*deg[x]; y=LCA(x,w); tmp+=(deg[x]+deg[w]-2*deg[y]); if (ans>tmp) p=x, ans=tmp; x=LCA(u,w); tmp=deg[u]+deg[w]-2*deg[x]; y=LCA(x,v); tmp+=(deg[x]+deg[v]-2*deg[y]); if (ans>tmp) p=x, ans=tmp; x=LCA(v,w); tmp=deg[v]+deg[w]-2*deg[x]; y=LCA(x,u); tmp+=(deg[x]+deg[u]-2*deg[y]); if (ans>tmp) p=x, ans=tmp; printf("%d %d\n",p,ans); } return 0; }
复杂度O(n+m*logn).