Jzoj 3054NOIP2012模拟10.27倍增祖孙询问
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jzoj 3054NOIP2012模拟10.27倍增祖孙询问相关的知识,希望对你有一定的参考价值。
Link
Jzoj【3054】【NOIP2012模拟10.27】祖孙询问
题面
Description
已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。
Input
输入第一行包括一个整数n表示节点个数。
接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。
第n+2行是一个整数m表示询问个数。
接下来m行,每行两个正整数x和y。
Output
对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。
Sample Input
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
Sample Output
1
0
0
0
2
Data Constraint
对于100%的.据,n,m≤40000,每个节点的编号都不超过40000。
解题思路
就tm离谱,第一次做这么简单的B组题
倍增往上跳,x和y跳到同等高度时,判断x和y是否是同一个点
Code
#include <iostream>
#include <cstdio>
#define N 40100
using namespace std;
struct DT{
int to, next;
}a[N];
int n, m, x, y, num, lg[N], dep[N], head[N], fa[N][50];
void add(int x, int y) { a[++num] = (DT){y, head[x]}, head[x] = num; }
void dfs(int x, int f) {
dep[x] = dep[f] + 1;
fa[x][0] = f;
for(int i = 1; i < lg[dep[x]]; i ++)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(int i = head[x]; i; i = a[i].next)
if(a[i].to != f)
dfs(a[i].to, x);
}
int find(int x, int y) {
int flag = 2; //默认y是x的祖先(因为我写LCA的时候,习惯跳x)
if(dep[x] < dep[y]) {
flag = 1; //x在上面,初始化x是y的祖先
swap(x, y);
}
for(int i = lg[dep[x] - dep[y]] - 1; i >= 0; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i]; //倍增往上跳
if(x == y) return flag; //同一个点,表示两点是祖孙关系
else return 0;
}
int main() {
scanf("%d", &n);
int S;
for(int i = 1; i <= n; i ++) {
scanf("%d %d", &x, &y);
if(y != -1) add(y, x);
else S = x;
}
for(int i = 1; i <= n; i ++) //求Log
lg[i] = lg[i - 1] + (i == (1 << lg[i - 1]));
dfs(S, 0);
scanf("%d", &m);
for(int i = 1; i <= m; i ++) {
scanf("%d %d", &x, &y);
printf("%d\\n", find(x, y));
}
}
以上是关于Jzoj 3054NOIP2012模拟10.27倍增祖孙询问的主要内容,如果未能解决你的问题,请参考以下文章
Jzoj 3056NOIP2012模拟10.27容斥DP数学数字
10.27 noip模拟试题(afternoon)(跪在游戏玩少了2333)