hdu 5266 pog loves szh III(lca + 线段树)

I - pog loves szh III
Time Limit:6000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u
Submit  Status  Practice  HDU 5266

Description

Pog and Szh are playing games. Firstly Pog draw a tree on the paper. Here we define 1 as the root of the tree.Then Szh choose some nodes from the tree. He wants Pog helps to find the least common ancestor (LCA) of these node.The question is too difficult for Pog.So he decided to simplify the problems.The nodes picked are consecutive numbers from  l_i to r_i ([l_i, r_i])

Hint : You should be careful about stack overflow !

Input

Several groups of data (no more than 3 groups, n \geq 10000 or Q \geq 10000). 

The following line contains ans integers,n (2 \leq n \leq 300000)

AT The following n-1 line, two integers are b_i and c_i at every line, it shows an edge connecting b_i and c_i

The following line contains ans integers,Q (Q \leq 300000)

AT The following Q line contains two integers li and ri(1 \leq li \leq ri \leq n).

Output

For each case,output  Q integers means the LCA of [l_i,r_i].

Sample Input

5
1 2
1 3
3 4
4 5
5
1 2
2 3
3 4
3 5
1 5

Sample Output

1
1
3
3
1

/*
hdu 5266 pog loves szh III(lca + 线段树)

problem:
给你一棵树,然后查询节点l~r的最小公共祖先

solve:
如果用在线算法,查询的时候可以直接O(1)实现,然后查询节点l~r的最小公共祖先感觉很像区间最值
而且可以发现 如果知道a~b和c~d的最小公共祖先,那么a~d的lca 就是a~b的lca和c~d的lca的最小公共祖先
所以考虑用线段树解决查询问题

hhh-2016-08-08 16:58:09
*/
#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#include <map>
#include <queue>
#include <vector>
#include <set>
#define lson (i<<1)
#define rson ((i<<1)|1)
using namespace std;
typedef long long ll;
const int maxn=300000 + 500;
const int INF=0x3f3f3f3f;
const int mod = 1e9+7;
int n,tot,cnt;
int head[maxn],rmq[maxn];
int flag[maxn];
int vis[maxn];
int P[maxn];
int F[maxn<<1];

struct Edge
{
    int from,to,next;
} edge[maxn << 1];

int fin(int x)
{
    if(F[x] == -1) return x;
    return F[x] = fin(F[x]);
}

void unio(int a,int b)
{
    int ta=  fin(a);
    int tb= fin(b);
    if(ta != tb)
        F[ta] = tb;
}

void add_edge(int u,int v)
{
    edge[tot].from = u,edge[tot].to = v,edge[tot].next=head[u],head[u] = tot++;
}

struct ST
{
    int m[maxn << 1];
    int dp[maxn << 1][20];
    void ini(int n)
    {
        m[0] = -1;
        for(int i = 1; i <= n; i++)
        {
            m[i] = ((i&(i-1)) == 0)? m[i-1]+1:m[i-1];
            dp[i][0] = i;
        }
        for(int j = 1; j <= m[n]; j++)
        {
            for(int i = 1; i+(1<<j)-1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]] ?
                           dp[i][j-1] : dp[i+(1 << (j-1))][j-1];
        }
    }
    int query(int a,int b)
    {
        if(a > b)
            swap(a,b);
        int k = m[b-a+1];
        return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]] ?
               dp[a][k]:dp[b-(1<<k)+1][k];
    }
};

ST st;

void dfs(int u,int pre,int dep)
{
    F[++cnt] = u;
    rmq[cnt] = dep;
    P[u] = cnt;

    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre)
            continue;
        dfs(v,u,dep+1);
        F[++cnt] = u;
        rmq[cnt] = dep;
    }
}

int query_lca(int a,int b)
{
    return F[st.query(P[a],P[b])];
}
void ini()
{
    memset(flag,0,sizeof(flag));
    memset(head,-1,sizeof(head));
    tot =0;
    cnt = 0;
}

struct node
{
    int l,r;
    int lca;
    int mid()
    {
        return (l+r)>>1;
    }
} tree[maxn << 2];

void push_up(int i)
{
    tree[i].lca = query_lca(tree[lson].lca,tree[rson].lca);
//    cout << tree[lson].lca << " " <<tree[rson].lca <<endl;
//    cout << tree[i].l<< " " << tree[i].r << " "  <<tree[i].lca <<endl;
}

void build(int i,int l,int r)
{
    tree[i].l = l,tree[i].r = r;
    if(l == r)
    {
        tree[i].lca = l;
//        cout << tree[i].l<< " " << tree[i].r << " "  <<tree[i].lca <<endl;
        return ;
    }
    int mid = tree[i].mid();
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(i);
}

int query(int i,int l,int r)
{
    if(tree[i].l >= l && tree[i].r <= r)
    {
        return tree[i].lca;
    }
    int mid = tree[i].mid();
    if(r <= mid)
        return query(lson,l,r);
    else if(l > mid)
        return query(rson,l,r);
    else
        return query_lca(query(lson,l,mid),query(rson,mid+1,r));
    push_up(i);
}

int main()
{
    int n,m,k;
    int a,b,c;
  //  freopen("in.txt","r",stdin);
    while(scanf("%d",&n) != EOF)
    {
        ini();

        for(int i = 1; i < n; i++)
        {
            scanf("%d%d",&a,&b);
            add_edge(b,a);
            add_edge(a,b);
            flag[b] = 1;
        }
        dfs(1,1,0);
        st.ini(2*n-1);
        scanf("%d",&m);
        build(1,1,n);
       // printf("1 2 %d\n",query_lca(1,2));
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d",&a,&b);
            printf("%d\n",query(1,a,b));
//printf("%d\n",query_lca(a,b));
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/Przz/p/5757303.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值