[LightOJ 1128]Greatest Parent
Posted lijilai-oi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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: ",i);//这句话非常关键QAQ while(q--) { ll k = read(),v = read(); printf("%d ",f(k,v)); } } return 0; }
以上是关于[LightOJ 1128]Greatest Parent的主要内容,如果未能解决你的问题,请参考以下文章