lightoj-1128-Greatest Parent(二分+LCA)
首先我要实力吐槽这个lightoj
它给我的注册密码藏在不为人所见的地方
注册注册了10多分钟
qwq
----------------------------------------------------------------
其次我要再吐槽一下这个难懂的题目
全英文emm...
百度翻译都救不了我
(我画图花半天,才懂emm...)
--------------------------------------------------------------
好的
我还是先解释一下题目吧
最最最一开始给你一个t
一共要整t次(t个不同的树)
每次的根节点的编号都为0
先给你2个数n、m
n个节点的树
m次询问
接下来的n-1行
第i行(1 <= i <= n-1)也有两个数x,y
x为i点的父节点的编号
y为i点的权值
再接下来的m行为m次询问
每行也有两个数x,y
每次查询x的父节点中,权值大于或等于y,离x最远的节点,输出它的编号
----------------------------------------------------------------------------------------------------------
基于倍增LCA思想上又用了二分
和倍增LCA一样
首先需要预处理出来fa[ ][ ]数组
于是就开始二分找到最深的节点
---------------------------------------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#define N 500100
using namespace std;
int n,m,dn[N],fa[N][25],dq,last,t,tt;
inline int lca(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 lca(l,fa[l][last]);
else if(dn[fa[l][last]] > dq)
return lca(fa[l][last],r);
return fa[l][last];
}
int main()
{
int t;
scanf("%d",&t);
int tt = t;
while(t--)
{
memset(fa,-1,sizeof(fa));
scanf("%d%d",&n,&m);
for(int i = 1; i < n; i++)
{
int x ,y;
scanf("%d%d",&x,&y);
dn[i] = y;
fa[i][0] = x;
}
dn[0] = 1;
printf("Case %d:\n",tt - t);
for(int i = 0; i < n; i++)
{
for(int j=1; j <= 20; j++)
{
if(fa[i][j - 1] == -1)
continue;//超出深度
fa[i][j] = fa[fa[i][j-1]][j - 1];
}
}
for(int i = 1; i <= m; i++)
{
last = 20;
int x;
scanf("%d%d",&x,&dq);
printf("%d\n",lca(x,0));
}
}
return 0;
}