题解:P17553 [JAG 2026 Summer Camp #2] Edge Exchanges
想介绍一个用树剖维护的
首先考虑为什么对于
用时间戳可以
然后考虑如何找到合法边。对于一组询问
然后我们发现直接二分不好处理中点位置,那就考虑维护重链上所有点的信息,两个点不在同一个重链上的时候就考虑较深点的链顶,像这样考虑的链顶不会超过
#include <bits/stdc++.h>
#define mid ((l+r)>>1)
#define pr pair<int,int>
#define fr first
#define sd second
using namespace std;
namespace l_mid_r{
const int N=5e5+5,K=23;
int n,tota,totb,cnt,ans[N];
int dfna[N],dfnb[N],in[N],out[N];
int fa[N],sz[N],top[N],son[N],id[N];//在哪个重链上
int pos[N];//在重链的哪个位置
int st[N][K];
unordered_map<int,int> mp[N];
pr e[N];
vector<int> a[N],b[N],line[N];
void dfs(int x,int pre){
dfna[x]=++tota,in[x]=tota;
for(int i:a[x]){
if(i==pre) continue;
dfs(i,x);
}
out[x]=tota;
}
void dfs1(int x,int pre){
fa[x]=pre,sz[x]=1;
for(int i:b[x]){
if(i==pre) continue;
dfs1(i,x),sz[x]+=sz[i];
if(sz[i]>sz[son[x]]) son[x]=i;
}
}
void dfs2(int x,int tp){
if(tp==x) cnt++,id[x]=cnt;
id[x]=id[tp],line[id[x]].push_back(x),pos[x]=line[id[x]].size()-1;
top[x]=tp,dfnb[x]=++totb,st[totb][0]=fa[x];
if(son[x]) dfs2(son[x],tp);
for(int i:b[x])
if(i!=fa[x]&&i!=son[x]) dfs2(i,i);
}
int get(int u,int v){return dfnb[u]<dfnb[v]?u:v;}
int lca(int u,int v){
if(u==v) return u;
if((u=dfnb[u])>(v=dfnb[v])) swap(u,v);
int k=__lg(v-u++);
return get(st[u][k],st[v-(1<<k)+1][k]);
}
bool check(int x,int y,int u){//0在下,1在上
if(dfna[x]<dfna[y]) swap(x,y);
return (in[x]<=dfna[u]&&dfna[u]<=out[x]);
}
int sol(int u,int v,int x,int y){
while(top[u]!=top[v]){
if(fa[top[u]]==v){
if(check(x,y,top[u])^check(x,y,v)) return mp[top[u]][v];
else v=top[u];
}else{
if(check(x,y,fa[top[u]])^check(x,y,v)) u=fa[top[u]];
else v=fa[top[u]];
}
}
int k=id[u],l=pos[v],r=pos[u];
while(l+1<r){
if(check(x,y,line[k][mid])^check(x,y,line[k][l])) r=mid;
else l=mid;
}
return mp[line[k][l]][line[k][r]];
}
int main(){
scanf("%d",&n);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
e[i]={u,v};
a[u].push_back(v);
a[v].push_back(u);
}
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
mp[u][v]=mp[v][u]=i;
b[u].push_back(v);
b[v].push_back(u);
}
dfs(1,0),dfs1(1,0),dfs2(1,1);
for(int i=1;i<K;i++)
for(int j=1;j+(1<<i)-1<=n;j++)
st[j][i]=get(st[j][i-1],st[j+(1<<(i-1))][i-1]);
for(int i=1;i<n;i++){
int u=lca(e[i].fr,e[i].sd);
if(check(e[i].fr,e[i].sd,u)^check(e[i].fr,e[i].sd,e[i].fr))
ans[i]=sol(e[i].fr,u,e[i].fr,e[i].sd);
else ans[i]=sol(e[i].sd,u,e[i].fr,e[i].sd);
}
for(int i=1;i<n;i++) printf("%d\n",ans[i]);
return 0;
}
}
signed main(){return l_mid_r::main();}