牛客 城市网络(倍增)

这题暴力思路是一直往上跳,然后计算,但是我们发现,如果知道了父节点的所有信息,那么我们只需要比一下父节点的信息和自己,就知道自己能怎么跳

问题就是如何快速求信息,因此想到从根节点往下求,用倍增算法。我们是设f[i][j]为i能够交易2的j次的点在哪,所以只要知道f[i][0]就可以通过倍增思想求出所有。

现在的问题就是如果求f[i][0],因为我们从父节点往下求,因此现在知道所有父节点信息,所以拿父节点的信息和自己比大小,跳到小于等于自己的最远距离

存在两种情况,一是父节点就比自己大,第二个就是在刚刚走到的位置再往上一格。

所有跳出根或者到不了的都为0,因为初始为c,只要多一条c和出发点的边就行。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int f[N][21];
int to[N];
int depth[N];
int e[N],ne[N],h[N],idx;
int a[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int n,q;
void dfs(int u,int fa){
    int i;
    int x=fa;
    for(i=20;i>=0;i--){
        if(f[x][i]&&a[f[x][i]]<=a[u])//一直跳直到不能跳
            x=f[x][i];
    }
    if(a[x]>a[u]) //判断是否u的父节点就大于u
        f[u][0]=x;
    else{
        f[u][0]=f[x][0];
    }
    depth[u]=depth[fa]+1;//根据深度判断是否已经跳过目标点
    for(i=1;i<=20;i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        dfs(j,u);
    }
}
int main(){
    cin>>n>>q;
    memset(h,-1,sizeof h);
    int i;
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    for(i=1;i<n;i++){
        int x,b;
        scanf("%d%d",&x,&b);
        add(x,b);
        add(b,x);
    }
    for(i=n+1;i<=n+q;i++){
        int x,b,c;
        scanf("%d%d%d",&x,&b,&c);
        add(x,i);
        a[i]=c;
        to[i-n]=b;
    }
    dfs(1,0);
    ll ans=0;
    for(i=1;i<=q;i++){
        int v=to[i];
        ans=0;
        int u=i+n;
        for(int j=20;j>=0;j--){
            if(depth[f[u][j]]>=depth[to[i]]){ //根据深度判断,因为树已经重构,不知道v在哪
                ans+=1<<j;
                u=f[u][j];
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2020-05-10 14:36  朝暮不思  阅读(163)  评论(0编辑  收藏  举报