题面
题意
给出一棵树,每个点都有一个权,每次查询一个点的祖先中比某个数大的最大深度.
已知父节点的权绝对严格小于其子节点
方法
建树之后,利用倍增进行与二分类似的思想进行查找,fa[i][j]记录点i向上(1 << j)代的父亲.
每次查找都找不超过当前范围的最大祖宗.
代码
#include<bits/stdc++.h>
#define N 500100
using namespace std;
int T,TT,n,m,dn[N],fa[N][25],dq,last,ds[N];
struct Bn
{
int next,to;
}bn[200100];
inline int find(int l,int r)
{
last--;
if(l==r||dn[l]>=dq&&dn[fa[l][0]]<dq) return l;
while(fa[l][last]==-1||dn[fa[l][last]]<dn[r])
last--;
if(dn[fa[l][last]]<dq)
{
return find(l,fa[l][last]);
}
else if(dn[fa[l][last]]>dq)
{
return find(fa[l][last],r);
}
return fa[l][last];
}
int main()
{
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
int i,j,p,q;
cin>>T;
TT=T;
while(T--)
{
memset(fa,-1,sizeof(fa));
scanf("%d%d",&n,&m);
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&p,&q);
dn[i]=q;
fa[i][0]=p;
ds[p]++;
}
dn[0]=1;
printf("Case %d:\n",TT-T);
for(i=1;i<=20;i++)
{
for(j=0;j<n;j++)
{
if(fa[j][i-1]==-1) continue;
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&p,&dq);
last=20;
printf("%d\n",find(p,0));
}
}
}