[hihoCoder - 1995]: Minimum value of edge weight between two points on a tree [LCA or tree dissection]

Title:

hihoCoder-1995: Shortest Edge on a Tree

Title:

Q Queries on the Minimum Value of the Boundary Weight between Two Points on a Tree

Notes:

(1) Like the LCA between two points on a tree, it can preprocess the multiplication array and process the minimum edge weight of the multiplication path. Then it can take the minimum value when jumping. Compared with the LCA by multiplication, it has one more array, and the single complexity is log.

#include <bits/stdc++.h>

using namespace std;
const int maxn = 2e5+15;
int u,v,p,w,n,q,cnt,head[maxn];
struct edge{
    int to,nxt,w;
}e[maxn<<1];
inline void add(int u,int v,int w){
    e[++cnt] = (edge){v,head[u],w};
    head[u] = cnt;
}
int dp[maxn][20],f[maxn],d[maxn],g[maxn][20];
void dfs(int x,int fa,int depth){
    dp[x][0] = fa; f[x] = fa; d[x] = depth;
    for(int i = head[x];i > 0;i = e[i].nxt){
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v,x,depth+1); g[v][0] = e[i].w;
    }
}
void init(){
    for(int i = 1;(1<<i)+1<=n; ++i){
        for(int j = 1;j <= n; ++j){
            dp[j][i] = dp[dp[j][i-1]][i-1];
            g[j][i] = min(g[j][i-1],g[dp[j][i-1]][i-1]);
        }
    }
}
int solve(int u,int v){
    int ans = 0x3f3f3f3f;
    if(d[u] < d[v]) swap(u,v);
    int h = d[u] - d[v];
    for(int i = 0;i < 20; ++i){
        if(h&(1<<i)){
            ans = min(ans,g[u][i]);
            u = dp[u][i];
        }
    }
    if(u == v) return ans;
    for(int i = 19; ~i; --i){
        if(dp[u][i] != dp[v][i]){
            ans = min(min(g[u][i],g[v][i]),ans);
            u = dp[u][i]; v = dp[v][i];
        }
    }
    return min(ans,min(g[u][0],g[v][0])); //The last one to jump is the son node of LCA, so the minimum is required.
}
int main(){
    scanf("%d %d",&n,&q);
    for(int i = 1;i <= n; ++i){
        scanf("%d %d",&p,&w);
        if(p == 0) continue;
        add(i,p,w); add(p,i,w);
    }
    dfs(1,0,1); init();
    while(q--){
        scanf("%d %d",&u,&v);
        printf("%d\n",solve(u,v));
    }
    return 0;
}

(2) Tree Chain Partitioning + Line Segment Tree, single query complexity log^2, very humiliating, this code WA several pages; tree partitioning understanding is not deep enough, so I wrote this blog.

Code:

#include <bits/stdc++.h>

#define Min(x,y) (x)<(y)?(x):(y)
using namespace std;
const int maxn = 2e5+15;
int cnt,n,q,p,w,head[maxn];
struct edge{
    int to,nxt,w;
}e[maxn<<1];
inline void add(int u,int v,int w){
    e[++cnt] = (edge){v,head[u],w};
    head[u] = cnt;
}
int sz[maxn],son[maxn],d[maxn],f[maxn],val[maxn];
void dfs1(int x,int fa,int depth){
    f[x] = fa, sz[x] = 1, d[x] = depth;
    for(int i = head[x];i > 0;i = e[i].nxt){
        int v = e[i].to;
        if(v == fa) continue;
        dfs1(v,x,depth+1); val[v] = e[i].w;  //Decentralization of Border Power into Point Power
        sz[x] += sz[v];
        if(sz[v] > sz[son[x]]) son[x] = v;
    }
}
int A[maxn],tot,id[maxn],top[maxn];
void dfs2(int x,int t){
    A[++tot] = x, id[x] = tot, top[x] = t;
    if(!son[x]) return ; dfs2(son[x],t);
    for(int i = head[x];i > 0;i = e[i].nxt){
        int v = e[i].to;
        if(v != f[x] && v != son[x]) dfs2(v,v);
    }
}
int tr[maxn<<2],u,v;
void build(int l,int r,int x){
    if(l == r){
        tr[x] = val[A[l]];
        return ;
    }
    int mid = (l+r) >> 1;
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
    tr[x] = Min(tr[x<<1],tr[x<<1|1]);
}
void query(int l,int r,int L,int R,int x,int &ans){
    if(l > R || r < L) return;
    if(l >= L && r <= R){
        ans = Min(ans,tr[x]);
        return ;
    }
    int mid = (l+r)>>1;
    query(l,mid,L,R,x<<1,ans);
    query(mid+1,r,L,R,x<<1|1,ans);
}
int solve(int u,int v){
    int ans = 2e9;
    while(top[v] != top[u]){
        if(d[top[u]] < d[top[v]]) swap(u,v); //Don't write like I did: D [u] < D [v] 
        query(1,n,id[top[u]],id[u],1,ans);
        u = f[top[u]];
    }
    if(id[u] > id[v]) swap(u,v);
    if(u != v) query(1,n,id[u]+1,id[v],1,ans);
    return ans;
}
int main(){
    scanf("%d %d",&n,&q);
    for(int i = 1;i <= n; ++i){
        scanf("%d %d",&p,&w);
        if(p==0 && w==0) continue;
        add(i,p,w); add(p,i,w);
    }
    dfs1(1,0,1); dfs2(1,1); 
    val[1]=2e9; build(1,n,1);
    while(q--){
        scanf("%d %d",&u,&v);
        printf("%d\n",solve(u,v));
    }
    return 0;
}

 

Posted by vinylblare on Mon, 07 Oct 2019 09:12:26 -0700