牛客 城市网络(倍增)
这题暴力思路是一直往上跳,然后计算,但是我们发现,如果知道了父节点的所有信息,那么我们只需要比一下父节点的信息和自己,就知道自己能怎么跳
问题就是如何快速求信息,因此想到从根节点往下求,用倍增算法。我们是设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; }
没有人不辛苦,只有人不喊疼