二叉搜索树上的LCA(最近公共祖先)

1017: Easy Tree Query

时间限制: 3 Sec   内存限制: 128 MB
提交: 184   解决: 30
[ 提交][ 状态][ 讨论版]

题目描述

You are given a binary search tree with depth k, whose nodes are valued from 1 to (2k − 1) and then Q queries.
For each query, you are given p nodes. Find the root of a smallest subtree which contains all p nodes and print its  value.

输入

The first line of input contains an integer T (T ≤ 100), the number of test cases. The first line of each test case  contains two integers k (1 ≤ k ≤ 60) and Q (1 ≤ Q ≤ 10 4 ). In next Q lines, each line contains an integer p and then  p integers — the values of nodes in this query. It is guaranteed that the total number of nodes given in each test  case will not exceed 105 .

输出

For each query, print a line contains the answer of that query.

样例输入

1

4 1

3 10 15 13

样例输出

12


#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<cstdlib>
#include<iostream>
using namespace std;
typedef long long ll;
#define mem(a,x) memset(a,x,sizeof a)
const int maxn = (int)1e5 + 5;
int T,k,q,p;
ll ans, aa[maxn];
// 基本的递归查找,二分查找,
//如果mid 比y大,说明x,y的父节点在当前树的左子树。
// 如果mid 比 x 小,说明x,y的父节点在当前树的右子树。
//一旦找到mid 在 x y 中间,则直接返回mid
ll get_lca(ll l,ll r, ll x ,ll y){
    if(x > y) swap(x,y);
    ll mid = l + (r - l) / 2;
    if(y < mid) return get_lca(l,mid-1,x,y);
    if(x > mid) return get_lca(mid+1, r,x,y);
    return mid;
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&k, &q);
        while(q--){
            scanf("%d",&p);
            for(int i=1;i<=p;i++)
                scanf("%lld",&aa[i]);
            ans = aa[1];
            ll n = (1ll << k)-1;
            for(int i=2;i<=p;i++)
                ans = get_lca(1,n,ans,aa[i]);
            printf("%lld\n",ans);
        }

    }
    return 0;
}


比赛的时候想复杂了。通过将二叉搜索树上的值转化为二进制,然后找到了规律,每次都将当前的两个数转化为二进制,然后找到第一个不同的二进制位,先判断置为0可否,再判断了置为1可否。超时。

超时代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll arr[maxn];int n=4,m;
ll getone(ll pre, ll old){
    if(pre == old) return pre;
    if(pre >old) swap(pre,old);
    ll ppre = pre;
    ll pold = old;
    vector<int>v1;
    vector<int>v2;
    while(pre){
        v1.push_back(pre%2);
        pre>>=1;
    }
    while(old){
        v2.push_back(old%2);
        old>>=1;
    }
    while(v1.size() < n) v1.push_back(0);
    while(v2.size() < n) v2.push_back(0);
 
//    reverse(v1.begin(),v1.end());
//    reverse(v2.begin(),v2.end());
    ll ans = 0;
    int k = n-1;
//
//        for(int i=0;i<v1.size();i++)
//        cout<<v1[i]<<" ";
//    cout<<endl;
//     for(int i=0;i<v2.size();i++)
//        cout<<v2[i]<<" ";
//    cout<<endl;
 
    for(int i=n-1;i>=0;i--){
        if(v1[i] != v2[i]){
            if(ans >= ppre && ans<= pold){
                return ans;
            }else{
                   ll ans1 = ans + (1<<k);
                    return ans1;
            }
        }else{
            if(v1[i] == 1)
                ans += (1<<k);
            k--;
        }
    }
}
int main(){
    //cout<<getone(2,4)<<endl;
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        ll top  =  1<<(n-1);
        int topn = n-1;
        while(m--){
            int q;scanf("%d",&q);
            ll pre;
            for(int i=0;i<q;i++){
                scanf("%lld",&arr[i]);
                if(i == 0) pre = arr[i];
                else{
                    pre = getone(pre,arr[i]);
                }
            }
            printf("%lld\n",pre);
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值