传送门
解析:
有一道差不多。但是我用了在线算法做的题:链接
这里用一种好想的多的离线算法来做这道题。
思路:
其实还是断边,将一个询问变成两个来做显然需要断的是两个点路径中点。
然后将询问分为两类处理, r o o t = u , b a n = v root=u,ban=v root=u,ban=v, u u u在 v v v的子树中或不在 v v v的子树中,其实就算 v = = l c a v==lca v==lca,我们还是可以这样做,但是需要修改一点,因为 l c a lca lca以上的部分到两者的距离是相等的,会影响答案,所以我们随便偏一点就好了。
u
u
u在
v
v
v的子树中,则
u
u
u无法从子树中出去,最远点就在
v
v
v的子树中询问。
u
u
u在
v
v
v的子树中,则
u
u
u无法进入子树,最远点就在
v
v
v的子树以外的地方询问。
然后预处理一下 D F S DFS DFS序,发现向相邻节点走一步实际上就是改变了其他节点到当前位置的距离,子树内的距离-1,其他地方距离+1。
所以我们维护一颗支持区间加,区间询问最大值的线段树就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=1000006,logN=20;
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}
int fa[N][logN+1],dep[N],in[N],out[N],pos[N],tot;
inline void dfs1(int u){
pos[in[u]=++tot]=u;
for(int re i=1;i<=logN;++i)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u][0])continue;
fa[v][0]=u;
dep[v]=dep[u]+1;
dfs1(v);
}
out[u]=tot;
}
inline int jump(int u,int step){
for(int re i=logN;~i;--i){
if((1<<i)<=step){
step-=1<<i;
u=fa[u][i];
}
}
return u;
}
inline int LCA(int u,int v){
if(dep[u]>dep[v])swap(u,v);
if(dep[u]<dep[v])v=jump(v,dep[v]-dep[u]);
if(v==u)return u;
for(int re i=logN;~i;--i){
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
}
int add[N<<2],maxn[N<<2];
inline void pushnow(int k,int val){maxn[k]+=val,add[k]+=val;}
inline void pushdown(int k){if(add[k]){pushnow(k<<1,add[k]);pushnow(k<<1|1,add[k]);add[k]=0;}}
inline void pushup(int k){maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);}
inline void build(int k,int l,int r){
if(l==r){
maxn[k]=dep[pos[l]];
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
inline void modify(int k,int l,int r,cs int &ql,cs int &qr,cs int &val){
if(ql>qr)return ;
if(ql<=l&&r<=qr)return pushnow(k,val);
pushdown(k);
int mid=(l+r)>>1;
if(ql<=mid)modify(k<<1,l,mid,ql,qr,val);
if(qr>mid)modify(k<<1|1,mid+1,r,ql,qr,val);
pushup(k);
}
inline int query(int k,int l,int r,cs int &ql,cs int &qr){
if(ql>qr)return -0x3f3f3f3f;
if(ql<=l&&r<=qr)return maxn[k];
pushdown(k);
int mid=(l+r)>>1;
if(qr<=mid)return query(k<<1,l,mid,ql,qr);
if(ql>mid)return query(k<<1|1,mid+1,r,ql,qr);
return max(query(k<<1,l,mid,ql,qr),query(k<<1|1,mid+1,r,ql,qr));
}
int n,m;
struct Query{
int root,pos,id;
friend bool operator<(cs Query &a,cs Query &b){
return in[a.root]<in[b.root];
}
}q1[N],q2[N];
int ans1[N],ans2[N],h1=1,h2=1;
inline void dfs2(int u){
while(h1<=m&&q1[h1].root==u)
ans1[q1[h1].id]=query(1,1,n,in[q1[h1].pos],out[q1[h1].pos]),++h1;
while(h2<=m&&q2[h2].root==u)
ans2[q2[h2].id]=max(query(1,1,n,1,in[q2[h2].pos]-1),query(1,1,n,out[q2[h2].pos]+1,n)),++h2;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u][0])continue;
modify(1,1,n,in[v],out[v],-1);
modify(1,1,n,1,in[v]-1,1);
modify(1,1,n,out[v]+1,n,1);
dfs2(v);
modify(1,1,n,in[v],out[v],1);
modify(1,1,n,1,in[v]-1,-1);
modify(1,1,n,out[v]+1,n,-1);
}
}
signed main(){
n=getint();
for(int re i=1;i<n;++i){
int u=getint(),v=getint();
addedge(u,v);
}
fa[1][0]=1;
dfs1(1);
build(1,1,n);
m=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint();
if(dep[u]>dep[v])swap(u,v);
int lca=LCA(u,v),dist=dep[u]+dep[v]-2*dep[lca];
int pos=jump(v,(dist-1)/2);
q1[i]=(Query){v,pos,i};
q2[i]=(Query){u,pos,i};
}
sort(q1+1,q1+m+1);
sort(q2+1,q2+m+1);
dfs2(1);
for(int re i=1;i<=m;++i)printf("%d\n",max(ans1[i],ans2[i]));
return 0;
}