给定一棵 \(n\) 个节点的树和 \(m\) 个询问,每个询问要求回答不在 \(u\) 和 \(v\) 两节点所形成的路径上的点的最小标号。要求强制在线 .
\(1\leq n,q\leq 10^6\)
首先,根节点就是 \(0\) 号节点 .
如果 \(u\) 和 \(v\) 的路径不经过 \(0\) 号节点,那么,答案就是 \(0\) .
那么,\(u\) 和 \(v\) 必定是 \(0\) 号节点同一个子树中的点 .
否则,如果 \(u\) 和 \(v\) 经过了根节点,即 \(0\) 号节点 .
那么,路径必定是 \(0\rightarrow u\) 和 \(0\rightarrow v\) 拼在一起的 . 那么,\(u\) 和 \(v\) 处在不同的子树 .
答案的构成是 \(u\) 所在子树中 \(0\rightarrow u\) 之外的点的最小编号 + \(v\) 所在子树中 \(0\rightarrow v\) 之外的点的最小编号 + 除了 \(u,v\) 所在子树以外所有 \(0\) 的子树中的最小编号 .
那么 \(u\) 所在子树中 \(0\rightarrow u\) 之外的点的最小编号和 \(v\) 所在子树中 \(0\rightarrow v\) 之外的点的最小编号可以预处理出来,用 \(dp(x)\) 表示 .
但是,如何 \(O(1)\) 地求出除了 \(u,v\) 所在子树以外所有 \(0\) 的子树中的最小编号呢?
可以先求出每个子树中的最小编号,保留前三小的最小编号 . 枚举前三小,必定有一棵树不是 \(u,v\) 所在的子树,那么,这些子树的最小编号就是上述值 .
因此,就是可以每次询问 \(O(1)\) 地求出最小值 .
这个题目在 hdu 上我提交了死活过不去 QwQ,手写了链接表和换做 bfs ,又加上了长长的优化之后都不可以. 但是,这个代码在学校的网站上却跑到了最快,737ms ,嘿嘿 .
时间复杂度 : \(O(n+m)\)
空间复杂度 : \(O(n)\)
第一次提交 : Time Limited Exceed
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("Ofast")
#pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
while(ch<‘0‘||ch>‘9‘)ch=getchar();
int res=0;
while(ch>=‘0‘&&ch<=‘9‘){
res=res*10+ch-‘0‘;
ch=getchar();
}
return res;
}
inline void print(int res){
int a[8];
int len=0;
while(res>0){
a[len++]=res%10;
res/=10;
}
for(int i=len-1;i>=0;i--)putchar(‘0‘+a[i]);
putchar(‘\n‘);
}
const int inf=1e9+10;
int n,q;
int head[1000010],nxt[2000010],to[2000010],cnt=0;
int id[1000010],dp[1000010],mn[1000010],mn2[1000010];
int fa[1000010];
int st=0,ed=0;
int Q[1000010];
int len=0;
int a[1000010];
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
for(int i=0;i<1000010;i++)id[i]=head[i]=-1,dp[i]=mn[i]=mn2[i]=inf;
while(~scanf("%d%d",&n,&q)){
for(int i=0;i<n-1;i++){
int u=read()-1,v=read()-1;
nxt[cnt]=head[u];to[cnt]=v;head[u]=cnt++;
nxt[cnt]=head[v];to[cnt]=u;head[v]=cnt++;
}
for(int i=head[0];i!=-1;i=nxt[i]){
st=ed=len=0;
Q[ed++]=to[i];fa[to[i]]=0;
while(st<ed){
int x=Q[st++];id[x]=to[i];a[len++]=x;
for(int j=head[x];j!=-1;j=nxt[j]){
if(to[j]!=fa[x]){
fa[to[j]]=x;
Q[ed++]=to[j];
}
}
}
for(int j=len-1;j>=0;j--){
mn[a[j]]=min(mn[a[j]],a[j]);
if(fa[a[j]]!=0)mn[fa[a[j]]]=min(mn[fa[a[j]]],mn[a[j]]);
}
st=ed=0;
Q[ed++]=to[i];
while(st<ed){
int x=Q[st++];
int tmp=inf;len=0;
dp[x]=mn2[x];
for(int j=head[x];j!=-1;j=nxt[j]){
if(to[j]!=fa[x]){
mn2[to[j]]=min(mn2[x],tmp);
tmp=min(tmp,mn[to[j]]);
a[len++]=to[j];
}
}
tmp=inf;
for(int j=len-1;j>=0;j--){
dp[x]=min(dp[x],mn[a[j]]);
mn2[a[j]]=min(mn2[a[j]],tmp);
tmp=min(tmp,mn[a[j]]);
}
for(int j=0;j<len;j++)Q[ed++]=a[j];
}
}
// for(int i=0;i<n;i++)cout<<id[i]<<" ";cout<<endl;
// for(int i=0;i<n;i++)cout<<mn[i]<<" ";cout<<endl;
// for(int i=0;i<n;i++)cout<<mn2[i]<<" ";cout<<endl;
// for(int i=0;i<n;i++)cout<<dp[i]<<" ";cout<<endl;
int num[4]={-1,-1,-1,-1};
for(int i=head[0];i!=-1;i=nxt[i]){
num[3]=to[i];
for(int j=2;j>=0;j--){
if(num[j]==-1||mn[num[j+1]]<mn[num[j]])
swap(num[j+1],num[j]);
}
}
// for(int i=0;i<3;i++)cout<<num[i]<<" ";cout<<endl;
int ans=0;
for(int t=0;t<q;t++){
int u=read()^ans,v=read()^ans;
u--;v--;
// cout<<u<<" "<<v<<": "<<id[u]<<" "<<id[v]<<endl;
ans=inf;
if(u==0||v==0){
if(u==v)ans=1;
else{
if(u!=0)swap(u,v);
ans=dp[v];
for(int i=0;i<3;i++){
if(num[i]!=id[v]&&num[i]!=-1){
ans=min(ans,mn[num[i]]);
}
}
}
}
else if(id[u]==id[v])ans=0;
else{
ans=min(dp[u],dp[v]);
for(int i=0;i<3;i++){
if(num[i]!=id[u]&&num[i]!=id[v]&&num[i]!=-1)
ans=min(ans,mn[num[i]]);
}
}
ans++;
print(ans);
}
for(int i=0;i<n;i++)dp[i]=mn[i]=mn2[i]=inf,id[i]=head[i]=-1;
cnt=0;
}
return 0;
}
/*inline? ll or int? size? min max?*/