题意是给定一棵以
1
为点的树,每次询问两个端点
树剖后的链的LCA的子树中包含了这条链,且子树在树剖形成的线段树上是连续的。
因此可以将链的
O(logn)
段置为
∞
。然后再查询,然后再恢复为原值。可以通过一个标记数组来实现。
时间复杂度是
O(nlog2n)
。
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+7;
const int INF=1e9+7;
int n,m,sz[N],son[N],top[N],id[N],d[N],fa[N],cnt,b[N];
vector<int> adj[N];
int tree[N<<2],valid[N<<2];
void dfs1(int u, int father, int deep)
{
d[u]=deep;
fa[u]=father;
sz[u]=1;
for (int i=0;i<adj[u].size();++i)
{
int v=adj[u][i];
if(v==father) continue;
dfs1(v,u,deep+1);
sz[u]+=sz[v];
if(son[u]==-1||sz[son[u]]<sz[v])
son[u]=v;
}
}
void dfs2(int u)
{
id[u]=++cnt;
if(son[u]!=-1)
{
top[son[u]]=top[u];
dfs2(son[u]);
}
for(int i=0;i<adj[u].size();++i)
{
int v=adj[u][i];
if(v!=fa[u]&&v!=son[u])
{
top[v]=v;
dfs2(v);
}
}
}
void init()
{
top[1]=1;
for(int i=1;i<=n;i++) adj[i].clear();
memset(son,-1,sizeof(son));
cnt=0;
}
inline void push_up(int rt)
{
tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
void build(int rt,int l,int r)
{
valid[rt]=true;
if(l==r)
{
tree[rt]=b[l];
return;
}
int m=(l+r)>>1;
if(l<=m) build(rt<<1,l,m);
if(r>m) build(rt<<1|1,m+1,r);
push_up(rt);
}
void update(int rt, int l,int r,int ql,int qr,bool val)
{
if(l>=ql&&r<=qr)
{
valid[rt]=val;
if(!valid[rt]) tree[rt]=INF;
if(valid[rt])
{
if(l==r) tree[rt]=b[l];
else push_up(rt);
}
return ;
}
int m=(l+r)>>1;
if(ql<=m) update(rt<<1, l ,m,ql,qr,val);
if(qr>m) update(rt<<1|1,m+1,r,ql,qr,val);
push_up(rt);
}
int query(int rt, int l, int r, int ql, int qr)
{
if(!valid[rt]) return INF;
if(l>=ql&&r<=qr)
{
return tree[rt];
}
int m=(l+r)>>1;
if(ql>m) return query(rt<<1|1,m+1,r,ql,qr);
else if(qr<=m) return query(rt<<1,l,m,ql,qr);
else return min(query(rt<<1|1,m+1,r,ql,qr),query(rt<<1,l,m,ql,qr));
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs1(1,0,0);
dfs2(1);
for(int i=1;i<=n;i++) b[id[i]]=i;
build(1,1,n);
while(m--)
{
int x,y,u,v;
scanf("%d%d",&x,&y);
u=x;v=y;
while (top[u]!=top[v])
{
if(d[top[u]]<d[top[v]]) swap(u,v);
update(1,1,n,id[top[u]],id[u],0);
u=top[u];
u=fa[u];
}
if(d[u]>d[v]) swap(u,v);
update(1,1,n,id[u],id[v],0);
int ans=query(1,1,n,id[u],id[u]+sz[u]-1);
if(ans==INF) ans=-1;
printf("%d\n",ans);
u=x;v=y;
while (top[u]!=top[v])
{
if(d[top[u]]<d[top[v]]) swap(u,v);
update(1,1,n,id[top[u]],id[u],1);
u=top[u];
u=fa[u];
}
if(d[u]>d[v]) swap(u,v);
update(1,1,n,id[u],id[v],1);
}
}
return 0;
}