HDU 5266 pog loves szh III

题意:给出一棵树,1为根节点,求一段区间内所有点的最近公共祖先。

 

解法:用一棵线段树维护区间LCA。LCA是dp做法。dp[i][j]表示点i的第2^j个祖先是谁,转移方程为dp[i][j] = dp[dp[i][j - 1]][j - 1],初始的dp[i][0]可以用一次dfs求得,这样可以用logn的时间求第x个祖先或查询LCA。求第x个祖先可以从二进制的角度理解,假设x是10,转化为二进制是1010,那么只要升2^3 + 2^1个深度就可以求出第x个祖先。求LCA的具体做法是,先将点a和b升至同一深度,如果此时a和b为同一个点,说明LCA就是a(或者b),如果不是同一个点,再同时向上升,直到已经无法找到两个点的祖先是不同点,说明两个点已经升至LCA的下一层,再向上升一层即为LCA。

然后就是建一棵线段树,只需要查询,没有更新,查询的写法纠结了好久……

因为代码写的太屎了,扩栈了依然会RE……所以只好用栈模拟……但是不扩栈又会T……不太理解那句扩栈用的语句的原理TUT……5000+ms擦边过了……

 

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:10240000000,10240000000")
using namespace std;
vector <int> tree[300005];
bool vis[300005];
int deep[300005];
int dp[300005][30];
int st[300005 << 2];
struct node
{
    int rt, dep;
    node(int rt, int dep) : rt(rt), dep(dep) {}
    node() {}
};
stack <node> s;
int LCA(int a, int b)
{
    if(deep[a] < deep[b])
        swap(a, b);
    for(int i = 20; i >= 0; i--)
    {
        if(deep[a] == deep[b])
            break;
        if(deep[dp[a][i]] >= deep[b])
            a = dp[a][i];
    }
    if(a == b)
        return a;
    for(int i = 20; i >= 0; i--)
    {
        if(dp[a][i] != dp[b][i])
        {
            a = dp[a][i];
            b = dp[b][i];
        }
    }
    return dp[a][0];
}
void pushUp(int rt)
{
    st[rt] = LCA(st[rt << 1], st[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
    if(l == r)
    {
        st[rt] = l;
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushUp(rt);
}
int query(int ll, int rr, int l, int r, int rt)
{
    if(ll <= l && rr >= r)
        return st[rt];
    int m = (l + r) >> 1;
    int res;
    if(ll <= m)
    {
        res = query(ll, rr, lson);
        if(rr > m)
            return LCA(res, query(ll, rr, rson));
        else
            return res;
    }
    else
        return query(ll, rr, rson);
}
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < 300005; i++)
            tree[i].clear();
        for(int i = 0; i < n - 1; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
        memset(vis, 0, sizeof vis);
        memset(dp, 0, sizeof dp);
        vis[1] = true;
        dp[1][0] = 1;
        s.push(node(1, 1));
        while(!s.empty())
        {
            node top = s.top();
            deep[top.rt] = top.dep;
            int len = tree[top.rt].size();
            int flag = true;
            for(int i = 0; i < len; i++)
            {
                if(!vis[tree[top.rt][i]])
                {
                    vis[tree[top.rt][i]] = true;
                    dp[tree[top.rt][i]][0] = top.rt;
                    s.push(node(tree[top.rt][i], top.dep + 1));
                    flag = false;
                }
            }
            if(flag)
                s.pop();
        }
        for(int j = 1; j < 20; j++)
        {
            for(int i = 1; i <= n; i++)
            {
                dp[i][j] = dp[dp[i][j - 1]][j - 1];
            }
        }
        build(1, n, 1);
        int q;
        scanf("%d", &q);
        for(int i = 0; i < q; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            printf("%d\n", query(a, b, 1, n, 1));
        }
    }
    return 0;
}

  

posted @ 2015-06-09 13:28  露儿大人  阅读(176)  评论(0编辑  收藏  举报