1128 - Greatest Parent---LightOj(LCA+离线算法)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1128

给你一颗树,树的每个节点都有一个权值,树根是节点0,权值为1,树中每个节点的权值都是大于父节点的权值的;

然后给出每个节点的父节点以及该节点的权值;有Q个询问,每个询问有两个数u和val,求u的祖先中权值>=val的最大祖先,就是离u最远的那个>=val的祖先的节点;

数的范围较大有5w个Q,1w个n,所以我们不能直接模拟,也许这1w个节点是一串下来的,那么复杂度就变成了nQ必定会TLE;

我们知道每个节点i要找祖先中>=val的一定要从根节点到i的路径上去找,所以我们可以用二分;具体看代码吧;

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <math.h>

using namespace std;

#define met(a, b) memset(a, b, sizeof(a))
#define N 100053
#define INF 0x3f3f3f3f
const int MOD = 1e9+7;

typedef long long LL;

struct node
{
    int Index, val;
    node(){}
    node(int Index, int val) : Index(Index), val(val){}
};

int v[N], n, ans[N], Time, Node[N];
vector<vector<int> >G;
vector<vector<node> >Q;

int Find(int val)
{
    int L = 1, R = Time, ans = Time;
    while(L<=R)
    {
        int Mid = (L+R)/2;
        if(v[Node[Mid]] >= val)
        {
            R = Mid-1;
            ans = Mid;
        }
        else
            L = Mid+1;
    }
    return Node[ans];
}

void dfs(int u)
{
    Node[++Time] = u;///Node[i]表示从根节点0到节点i的深度;

    int len = Q[u].size();///在询问中 问u节点的我们可以从根节点到u节点这个路径上寻找v大于val的节点,用二分法;
    for(int i=0; i<len; i++)
    {
        node p = Q[u][i];
        ans[p.Index] = Find(p.val);///把结果保存起来;
    }

    for(int i=0, L=G[u].size(); i<L; i++)
        dfs(G[u][i]);

    Time--;///返回上一层,深度要减;
}

int main()
{
    int T, q, t = 1;
    scanf("%d", &T);
    while(T--)
    {
        met(v, 0);
        v[0] = 1;

        scanf("%d %d", &n, &q);

        G.clear();
        G.resize(n+5);

        Q.clear();
        Q.resize(n+5);

        int f, u, num;
        for(int i=1; i<n; i++)
        {
            scanf("%d %d", &f, &v[i]);
            G[f].push_back(i);
        }
        for(int i=1; i<=q; i++)
        {
            scanf("%d %d", &u, &num);
            Q[u].push_back(node(i, num));
        }

        Time = 0;
        dfs(0);

        printf("Case %d:\n", t++);
        for(int i=1; i<=q; i++)
            printf("%d\n", ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2016-08-06 10:42  西瓜不懂柠檬的酸  Views(296)  Comments(0Edit  收藏  举报
levels of contents