[LightOJ 1128]Greatest Parent

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

原题是英文题面,大概翻译了一下:

最大的祖先

树是一个连通的无环图,在这个问题中给出一个有根树,每个点有一个权值,每个点的权值严格的大于它父亲的权值。现在给出一个点以及一个整数的询问,你需要找到这个点最大的可能的祖先(也许可能包括这个点),它的权值大于或等于给出的整数。

输入

输入的开始是一个整数 T (T≤ 5), 表示测试数据的数量。

每一个情况的第一行是一个空行,下一列读入两个整数 N (1 ≤ N ≤ 105)q (1 ≤ q ≤ 50000) N表示点的个数,q表示询问的个数。点的标记从0到N-1。

然后将会有N-1行,第i行 (1 ≤ i < N) 包括两个整数 pi 和 si (0 ≤ pi < i, 1 ≤ si < 231)pi 表示这个点的父亲,si 表示这个点的权值。假设给出的树是正确的然后下面的限制是存在的。你可以假设第0个点为根节点并且它的点权为1。

以下q行每行包括一个询问,每个询问包括两个整数k和v (1 ≤ k < N, 1 ≤ v ≤ sk).

输出

对于每个情况,在一行输出情况编号,然后对于每个询问,输出最大的,点权大于等于v的祖先的编号k。你可以假设解是存在的。.

样例输入

样例输出

1

 

7 4

0 3

0 4

0 2

1 4

2 7

2 10

5 1

4 2

5 4

6 10

Case 1:

0

1

2

6

  因为是英文题面,在看题的时候难免有所疏漏或者理解错误,尤其是输入输出格式(之前因为要输出caseWA了n次)。一旦我们知道了输入输出格式,在仔细看题就不是特别复杂了。给出的这棵树满足儿子节点的点权一定比父亲大,那么我们可以利用倍增的思想解决问题,让x按照倍增方式不断向上爬,每爬到一个点就看看这个点的点权和询问的数相比哪个大,满足条件输出结果。如果不是倍增,一步一步向上复杂度为O(n),会被卡,而倍增为O(logn),可以通过。

参考代码

#include<cstdio>
#include<cmath>
#include<cstring>
#define ll int
#define N 200010
#define mm(a) memset(a,0,sizeof(a))
ll read()
{
    char ch = getchar();
    ll x = 0, f = 1;
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9')
    {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x * f;
}//快读
ll head[N],nxt[N],to[N],val[N],fa[N][31],dis[N];
ll t,n,q,cnt;
void reset()
{
    mm(head);
    mm(to);
    mm(val);
    mm(fa);
    mm(dis);
    cnt = 0;
}
void add(ll u,ll v)
{
    cnt++;
    nxt[cnt] = head[u];
    head[u] = cnt;
    to[cnt] = v;
}
void dfs(ll u,ll pa)
{
    for(ll i = 1;i <= 20;i++)
    {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];//预处理出所有的祖先
    }
    for(ll i = head[u];i;i = nxt[i])
    {
        dfs(to[i],u);
    }
}
ll f(ll x,ll num)
{
    for(ll i = 20;i >= 0;i--)
    {
        if(val[fa[x][i]] >= num)
        x = fa[x][i];//倍增往上爬
    }
    return x;
}
int main()
{
    t = read();
    for(int i = 1;i <= t;i++)
    {
        reset();
        val[0] = 1;
        dis[0] = 1;
        n = read();q = read();
        for(ll i = 1;i <= n - 1;i++)
        {
            ll p = read(),s = read();
            add(p,i);
            fa[i][0] = p;
            val[i] = s;
        }
        dfs(0,0);
        printf("Case %d:\n",i);//这句话非常关键QAQ
        while(q--)
        {
            ll k = read(),v = read();
            printf("%d\n",f(k,v));
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lijilai-oi/p/10691617.html