September 3rd 模拟赛C T1 祖孙询问 Solution

空降题目处(外网)
点我点我点我

空降题目处(内网)
点我点我点我

Description

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

Input

输入第一行包括一个整数n表示节点个数。
接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。
第n+2行是一个整数m表示询问个数。
接下来m行,每行两个正整数x和y。

Output

对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。

Solution

倍增…LCA…
你问我是什么?
自行脑补.(邓晗笑)

Code

C++

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m,a,b,t,x[80001],y[80001],s[40001],e[40001],d[40001][18],l[40001];

void sort(int l,int r);
void bfs(int t,int x,int la);
int ff(int x,int y);

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&x[i*2],&y[i*2]);
        x[i*2-1]=y[i*2];
        y[i*2-1]=x[i*2];
        if (y[i*2]==-1)
            t=x[i*2];
    }
    sort(1,n*2);
    for (int i=0;i<=n*2;i++)
        if (x[i]!=x[i+1])
        {
            e[x[i]]=i;
            s[x[i+1]]=i+1;
        }
    d[t][0]=-1;
    bfs(1,t,-1);
    t=1;
    for (int i=1;i<=17;i++)
    {
        t=t*2;
        for (int j=1;j<=40000;j++)
            if (l[j]>t)
                d[j][i]=d[d[j][i-1]][i-1];
    }
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        printf("%d\n",ff(a,b));
    }
}

void sort(int l,int r)
{
    int i=l,j=r,m=x[(l+r)/2];
    do
    {
        while (x[i]<m)
            i++;
        while (m<x[j])
            j--;
        if (i<=j)
        {
            swap(x[i],x[j]);
            swap(y[i],y[j]);
            i++;
            j--;
        }
    }
    while (i<=j);
    if (i<r)
        sort(i,r);
    if (l<j)
        sort(l,j);
}

void bfs(int t,int x,int la)
{
    l[x]=t;
    d[x][0]=la;
    for (int i=s[x];i<=e[x];i++)
        if (y[i]!=la)
            bfs(t+1,y[i],x);
}

int ff(int x,int y)
{
    int ans=2;
    if (l[x]<l[y])
    {
        swap(x,y);
        ans=1;
    }
    for (int i=17;i>=0;i--)
    {
        if (l[d[x][i]]>=l[y])
            x=d[x][i];
    }
    if (x==y)
        return ans;
    else
        return 0;
}

Pascal

var
    n,m,a,b,t,i,j:longint;
    x,y:array [0..100000] of longint;
    s,e,l:array [-1..50000] of longint;
    d:array [0..50000,0..17] of longint;

procedure swap(var x,y:longint);
var
    t:longint;

begin

    t:=x;
    x:=y;
    y:=t;

end;

procedure sort(l,r:longint);
var
    i,j,m:longint;

begin

    i:=l;
    j:=r;
    m:=x[(i+j) shr 1];
    repeat
        while x[i]<m do
            inc(i);
        while m<x[j] do
            dec(j);
        if i<=j then
        begin
            swap(x[i],x[j]);
            swap(y[i],y[j]);
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then
        sort(i,r);
    if l<j then
        sort(l,j);

end;

procedure bfs(t,x,la:longint);
var
    i:longint;

begin

    l[x]:=t;
    d[x][0]:=la;
    for i:=s[x] to e[x] do
        if y[i]<>la then
            bfs(t+1,y[i],x);

end;

function ff(x,y:longint):longint;
var
    ans,i:longint;

begin

    ans:=2;
    if l[x]<l[y] then
    begin
        swap(x,y);
        ans:=1;
    end;
    for i:=17 downto 0 do
    begin
        if (l[d[x][i]]>=l[y]) then
            x:=d[x][i];
    end;
    if x=y then
        exit(ans)
    else
        exit(0);

end;

begin

    read(n);
    for i:=1 to n do
    begin
        read(x[i*2],y[i*2]);
        x[i*2-1]:=y[i*2];
        y[i*2-1]:=x[i*2];
        if y[i*2]=-1 then
            t:=x[i*2];
    end;
    sort(1,n*2);
    for i:=0 to n*2 do
        if (x[i]<>x[i+1]) then
        begin
            e[x[i]]:=i;
            s[x[i+1]]:=i+1;
        end;
    d[t][0]:=-1;
    bfs(1,t,-1);
    t:=1;
    for i:=1 to 17 do
    begin
        t:=t*2;
        for j:=1 to 40000 do
            if l[j]>t then
                d[j][i]:=d[d[j][i-1]][i-1];
    end;
    read(m);
    for i:=1 to m do
    begin
        read(a,b);
        writeln(ff(a,b));
    end;

end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值