树上倍增——城市网络

传送门

题解:
题目中保证了u到v一定在最短路径上,所以考虑用树上倍增的方法。我们fa数组存的是比当前节点val值严格大的最近祖先。然后每次倍增的时候更新答案就可以了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+7;
int head[N],e[N<<1],ne[N<<1],fa[N][25],val[N],cnt,pre[N],dep[N];
void add(int a,int b)
{
    e[cnt]=b,ne[cnt]=head[a],head[a]=cnt++;
}
void dfs(int u,int f)
{
    dep[u]=dep[f]+1;
    if(val[u]<val[f]){
        fa[u][0]=f;
    } else{
        int x=f;
        for(int i=20;i>=0;i--){
            if(fa[x][i]&&val[u]>=val[fa[x][i]]){
                x=fa[x][i];
            }
        }
        fa[u][0]=fa[x][0];
    }
    for(int i=1;i<=20;i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int i=head[u];~i;i=ne[i]){
        int j=e[i];
        if(f==j) continue;
        dfs(j,u);
    }
}
int main()
{
    memset(head,-1,sizeof head);
    int n,q; scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",val+i);
    for(int i=1;i<n;i++) {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    for(int i=1;i<=q;i++){
        int u,v,c; scanf("%d%d%d",&u,&v,&c);
        add(i+n,u),add(u,i+n);
        val[i+n]=c,pre[i]=v;
    }
    dfs(1,0);
    for(int i=1;i<=q;i++){
        int u=i+n,v=pre[i],res=0;
        for(int j=20;j>=0;j--){
            if(dep[v]<=dep[fa[u][j]]){
                u=fa[u][j];
                res+=1<<j;
            }
        }
        printf("%lld\n",res);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值