The first line of each test case contains N(2 ≤ N ≤ 100,000) and Q(1 ≤ Q ≤ 100,000).
Each of the following N ‐ 1 lines of the test case contains two integers a(1 ≤ a ≤ N) and b(1 ≤ b ≤ N) indicating an edge between a and b.
Each of the following Q lines of the test case contains two integers X(1 ≤ X ≤ N) and Y(1 ≤ Y ≤ N, Y ≠ X) indicating an query.
1 7 3 1 2 1 5 2 3 2 4 5 6 5 7 1 2 5 3 3 2
3 3 no answers! 1 1
//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int inf=(1<<30);
const int maxn=220000;
struct PK
{
int u;
int dfn;
};
vector<PK> sot[maxn];
struct Node
{
int t;
int next;
};
int n;
Node G[maxn];
int p[maxn];
int l;
void init()
{
memset(p,-1,sizeof(p));
l=0;
}
void addedge(int u,int t)
{
G[l].t=t;
G[l].next=p[u];
p[u]=l++;
}
struct Pass
{
int st,ed;
};
Pass pas[maxn];
int dfn;
Node g[maxn];
int d[maxn];
int k;
void iinit()
{
memset(d,-1,sizeof(d));
k=0;
}
void iaddedge(int u,int t)
{
g[k].t=t;
g[k].next=d[u];
d[u]=k++;
}
struct TMin
{
int min1,min2;
};
TMin tmin[maxn];
int fa[maxn];
void solve(int u,int t)
{
if(t>=tmin[u].min2);
else if(t>=tmin[u].min1)
{
tmin[u].min2=t;
}
else
{
tmin[u].min2=tmin[u].min1;
tmin[u].min1=t;
}
}
void dfs(int u,int fath)
{
sot[u].clear();
fa[u]=fath;
pas[u].st=++dfn;
for(int i=p[u];i!=-1;i=G[i].next)
{
int t=G[i].t;
if(t==fath) continue;
solve(u,t);
iaddedge(u,t);
dfs(t,u);
PK tmp;tmp.u=t;tmp.dfn=pas[t].ed;
sot[u].push_back(tmp);
}
pas[u].ed=++dfn;
}
bool cmp(PK h,PK k)
{
return h.dfn<k.dfn;
}
struct node
{
int left,right,maxn,minc;
};
node tree[maxn*3];//构造线段树
int _max,_min;//当前最大值和最小者,查询是用
void buildtree(int id,int l,int r)//建树
{
tree[id].left=l;tree[id].right=r;//初始化左右端点
tree[id].maxn=-inf;tree[id].minc=inf;//初始化最大,小值
if(l!=r)//是根节点
{
buildtree(2*id,l,(l+r)/2);//左子树
buildtree(2*id+1,(l+r)/2+1,r);//右子树
}
}
void insert(int id,int i,int val)
{
if(tree[id].left==i&&tree[id].right==i)//叶子节点
{
tree[id].minc=tree[id].maxn=val;
return ;
}
tree[id].maxn=max(tree[id].maxn,val);//更新次节点的最大值
tree[id].minc=min(tree[id].minc,val);//更新次节点的最小值
if(i<=(tree[id].left+tree[id].right)/2) insert(2*id,i,val);//进去左子树
else insert(2*id+1,i,val);//进去右子树
}
void query(int id,int l,int r)//查询
{
if(l>r) return ;
if(tree[id].left==l&&tree[id].right==r)//叶子节点
{
_min=min(tree[id].minc,_min);
_max=max(tree[id].maxn,_max);
return ;
}
int mid=(tree[id].left+tree[id].right)/2;
if(r<=mid)//左子树
{
query(2*id,l,r);
}
else if(l>=mid+1)//右子树
{
query(2*id+1,l,r);
}
else//横跨左右子树
{
query(2*id,l,mid);//左
query(2*id+1,mid+1,r);//右
}
}
int main()
{
int ci;scanf("%d",&ci);
while(ci--)
{
int q;
scanf("%d%d",&n,&q);
init();
iinit();
for(int i=1;i<=n;i++) tmin[i].min1=tmin[i].min2=inf;
for(int i=0;i<n-1;i++)
{
int u,t;scanf("%d%d",&u,&t);
addedge(u,t);
addedge(t,u);
}
dfn=0;
dfs(1,inf);
for(int i=1;i<=n;i++)
{
sort(sot[i].begin(),sot[i].end(),cmp);
}
buildtree(1,1,n+n);
for(int i=1;i<=n;i++)
{
insert(1,pas[i].st,i);
insert(1,pas[i].ed,i);
}
while(q--)
{
int x,y;scanf("%d%d",&x,&y);//x!=y
if(pas[y].st<pas[x].st&&pas[y].ed>pas[x].ed)//x是y的子树
{
int ans=inf;
int first;
int t;
int l=0,r=sot[y].size();
while(l<r)
{
int mid=(l+r)/2;
if(sot[y][mid].dfn>=pas[x].ed) r=mid;
else l=mid+1;
}
t=sot[y][l].u;
//cout<<"t="<<t<<endl;
_max=-inf,_min=inf;//初始化
query(1,1,pas[y].st-1);
ans=min(ans,_min);
_max=-inf,_min=inf;//初始化
query(1,pas[y].st+1,pas[t].st-1);
ans=min(ans,_min);
_max=-inf,_min=inf;//初始化
query(1,pas[t].ed+1,pas[y].ed-1);
ans=min(ans,_min);
_max=-inf,_min=inf;//初始化
query(1,pas[y].ed+1,n+n);
ans=min(_min,ans);
if(tmin[y].min1==t)
{
first=min(tmin[y].min2,fa[y]);
}
else
{
first=min(tmin[y].min1,fa[y]);
}
if(ans!=inf) printf("%d %d\n",first,ans);
else printf("no answers!\n");
}
else //y是x的子树
{
_max=-inf,_min=inf;//初始化
query(1,pas[y].st+1,pas[y].ed-1);
if(_min!=inf) printf("%d %d\n",tmin[y].min1,_min);
else printf("no answers!\n");
}
}
printf("\n");
}
return 0;
}