[BZOJ1787] [Ahoi2008]Meet 緊急集合
阿新 • • 發佈:2018-03-11
return scrip while www tput markdown print examples bzoj
友鏈
Description
Examples
input
6 4
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6
output
5 2
2 5
4 1
6 0
Solution
兩兩算出LCA,有兩個LCA是相同的,選擇另一個作為答案
這道題似乎卡常數
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 500005
int head[MAXN];
int anc[20][MAXN],d[MAXN];
int N,M;
struct edge{
int v,next;
}G[MAXN<<1];
inline int read(){
int num = 0;char ch = getchar();
while(ch<‘0‘||ch>‘9‘)ch=getchar();
while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-48,ch=getchar();
return num;
}
int tot = 0;
inline void add(int u,int v){
G[++tot].v=v;G[tot].next=head[u];head[u]=tot;
}
inline void dfs(int u,int fa){
for(register int i=head[u];i;i=G[i].next){
int v = G[i].v;if(v==fa)continue;
d[v]=d[u]+1;anc[0][v]=u;
dfs(v,u);
}
}
inline void find_your_relative(){
for(register int i=1;i<=19;++i)
for(register int j=1;j<=N;++j)
anc[i][j] = anc[i-1 ][anc[i-1][j]];
}
inline int LCA(int u,int v){
if(d[u]<d[v])std::swap(u,v);
for(register int i=19;i>=0;i--)
if(d[anc[i][u]]>=d[v])u=anc[i][u];
if(u==v)return u;
for(register int i=19;i>=0;i--)
if(anc[i][u]!=anc[i][v])u=anc[i][u],v=anc[i][v];
return anc[0][u];
}
inline int dis(int u,int v){
int lca = LCA(u,v);
return d[u]+d[v]-(d[lca]<<1);
}
int main(){
N=read();M=read();
int u,v,a;
for(register int i=1;i<N;++i){
u=read();v=read();
add(u,v);add(v,u);
}
d[1]=1;anc[0][1]=0;
dfs(1,0);
find_your_relative();
for(register int i=1;i<=M;++i){
u=read();v=read();a=read();
int lca_uv = LCA(u,v);
int lca_ua = LCA(u,a);
int lca_va = LCA(v,a);
if(lca_uv==lca_ua)printf("%d %d\n",lca_va,d[v]+d[a]-(d[lca_va]<<1)+dis(lca_va,u));
else if(lca_uv==lca_va)printf("%d %d\n",lca_ua,d[u]+d[a]-(d[lca_ua]<<1)+dis(lca_ua,v));
else if(lca_ua==lca_va)printf("%d %d\n",lca_uv,d[v]+d[u]-(d[lca_uv]<<1)+dis(lca_uv,a));
}
return 0;
}
[BZOJ1787] [Ahoi2008]Meet 緊急集合