JZ3054祖孙询问

题目:

已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。

分析:

DFS序以及各种求LCA算法均可秒杀此题。

DFS遍历树,记录每个点X的第一次访问时间st[x]和最后一次访问时间ed[x],y在以X为根的子树中,则一定有st[x]<st[y]<ed[y]<ed[x]

附上代码:


const
  maxn=40000;


type
  arr=record
  y,next:longint;
end;


var
  n,m,test,temp:longint;
  a,b:array [0..maxn] of longint;
  cristine:array [0..maxn,0..20] of longint;
  elist:array [0..maxn*2] of arr;


procedure add(x1,y1:longint);
begin
  inc(test);
  with elist[test] do
    begin
      y:=y1;
      next:=a[x1];
      a[x1]:=test;
    end;
  inc(test);
  with elist[test] do
    begin
      y:=x1;
      next:=a[y1];
      a[y1]:=test;
    end;
end;


procedure init;
var
  i,x,y:longint;
begin
  test:=0;
  readln(n);
  for i:=1 to n do
    begin
      readln(x,y);
      if y=-1 then
        temp:=x
              else add(x,y);
    end;
end;


procedure dfs(x:longint);
var
  i:longint;
begin
  for i:=1 to 15 do
    begin
      if b[x]<(1 shl i) then
        break;
      cristine[x,i]:=cristine[cristine[x,i-1],i-1];
    end;
  i:=a[x];
  while i>0 do
    with elist[i] do
      begin
        if y<>cristine[x,0] then
          begin
            b[y]:=b[x]+1;
            cristine[y,0]:=x;
            dfs(y);
          end;
        i:=next;
      end;
end;


function lca(x,y:longint):longint;
var
  t,i:longint;
begin
  if b[x]<b[y] then
    begin
      t:=x;
      x:=y;
      y:=t;
    end;
  t:=b[x]-b[y];
  for i:=15 downto 0 do
    if (t and (1 shl i))<>0 then
      x:=cristine[x,i];
  for i:=15 downto 0 do
    if cristine[x,i]<>cristine[y,i] then
      begin
        x:=cristine[x,i];
        y:=cristine[y,i];
      end;
  if x=y then
    exit(x);
  exit(cristine[x,0]);
end;


procedure main;
var
  i,x,y,t:longint;
begin
  dfs(temp);
  readln(m);
  for i:=1 to m do
    begin
      readln(x,y);
      if x=y then
        writeln('0')
      else
        begin
          t:=lca(x,y);
          if t=x then
            writeln('1')
          else
            if t=y then
              writeln('2')
            else
              writeln('0');
        end;
    end;
end;


begin
  init;
  main;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值