最近公共祖先 LCA
dfs向上标记-O(n)
点A先向根搜索并标记,点B再向上搜索,第一次碰到的标记即是lca。
复杂度On,不常用
倍增法-O(logn)
dep[i]表示点i的深度
up[i,j]表示从i开始向root方向走2^j步数能走到的位置
若从i开始向根跳2^j次会跳出根则up[i,j]=0,dep[0]=0
具体过程:
【1】先让两点跳到同一层
【2】让两个点一起向根跳,直到跳到他们lca的下一层(一定要是下一层)
其中,从点i向根跳2j步等价于从点i跳2(j-1)次后再跳2^(j-1)次。如下图:
vct<ll> eg[N] ;
int dep[N] ;
int up[N][16] ;
void init(){
memset(dep , N , sizeof dep) ;
dep[root] = 1 ;
dep[0] = 0 ;
queue<int> q ;
q.push(root) ;
while(q.size()){
int now = q.front() ;
q.pop() ;
for(int nxt : eg[now]){
if(dep[nxt] > dep[now] + 1){
dep[nxt] = dep[now] + 1 ;
q.push(nxt) ;
up[nxt][0] = now ;
rep(i , 1 , 15){
up[nxt][i] = up[up[nxt][i - 1]][i - 1] ;
}
}
}
}
}
int lca(int a , int b){
if(dep[a] < dep[b]) swap(a , b) ;
drep(i , 0 , 15)//将ab放到同一层
if(dep[up[a][i]] >= dep[b])
a = up[a][i] ;
if(a == b) return b ;
drep(i , 0 , 15)//一起向上跳
if(up[a][i] != up[b][i]){
a = up[a][i] ;
b = up[b][i] ;
}
return up[a][0] ;
}
Tarjan离线lca-O(n+m)
根据dfs性质,搜索点i的时候会将点u的所有子树也搜索完。而我们可以在搜索完点u的子树的时候将和点i相关的query全部找一遍,若存在某个query其另一个点(点v)被搜索过,那么uv两点的LCA就是点v在并查集中的祖先。
/*
本代码用于求解任意树上两点的距离
acwing-1171-距离
*/
ll n , m , k ;
struct edge{
ll idx , len ;
};
vct<pii> query[N] ;
vct<edge> eg[N] ;
int ds[N] , ans[N] ;
int vis[N] , fa[N] ;
int find(int now){
return fa[now] = fa[now] == now ? now : find(fa[now]) ;
}
void dfs(int now , int pre){//初始化每个点到根的距离
//由于树是一个拓扑图,只要简单搜索即可
for(auto e : eg[now]){
int nxt = e.idx ;
int val = e.len ;
if(nxt == pre) continue ;
ds[nxt] = ds[now] + val ;
dfs(nxt , now) ;
}
}
void tarjan(int now){
vis[now] = 1 ;
for(auto e : eg[now]){
int nxt = e.idx ;
if(vis[nxt]) continue ;
tarjan(nxt) ;
fa[nxt] = now ;
}
for(auto q : query[now]){//和点now有关的所有询问
int idx = q.se ;
int node = q.fi ;
if(vis[node] == 0) continue ;
int lca = find(node) ;
ans[idx] = ds[node] + ds[now] - 2 * ds[lca] ;
}
vis[now] = 1 ;
}
void solve(){
cin >> n >> m ;
rep(i , 1 , n) fa[i] = i ;
rep(i , 1 , m) ans[i] = -1 ;
rep(i , 1 , n - 1){
ll u , v , w ;
cin >> u >> v >> w ;
if(u == v) continue ;
eg[u].pb({v , w}) ;
eg[v].pb({u , w}) ;
}
rep(i , 1 , m){
int u , v ;
cin >> u >> v ;
query[u].pb({v , i}) ;
query[v].pb({u , i}) ;
}
ds[1] = 0 ;
dfs(1 , -1) ;
tarjan(1) ;
rep(i , 1 , m) cout << ans[i] << "\n" ;
}//code_by_tyri
标签:nxt,int,up,dep,LCA,now,ds 来源: https://www.cnblogs.com/tyriis/p/16270247.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。