B20J :5165: 树上倍增
5165: 树上倍增
Description
现有一棵树。您需要写一个树上倍增算法,以实现如下操作:
A x 新建一个节点,将它作为x节点的儿子,编号为当前节点总数+1。
Q k p1 p2 p3.... 查询p1,p2,p3...这些节点的LCA。其中k表示查询节点的个数。
最初树上只有一个节点,编号为1。
多个节点的LCA定义为:这些节点的公共祖先中深度最大的。
Input
第一行,一个正整数,表示操作个数。
接下来行,每行输入一个操作,格式如题目描述所述。
保证任何输入的数都是正整数。
n≤3000000 k≤1000。
保证询问不超过1000次
Output
对于每一个Q操作,输出一行一个正整数,表示所询问节点的LCA。
Sample Input
10
A 1
A 2
A 3
A 1
A 5
A 5
Q 2 3 6
Q 2 6 7
Q 2 4 2
Q 3 7 6 5
A 1
A 2
A 3
A 1
A 5
A 5
Q 2 3 6
Q 2 6 7
Q 2 4 2
Q 3 7 6 5
Sample Output
1
5
2
5
思路:
如题目 : 树上倍增
#include <cstdio> #include <cstring> #include <algorithm> #include <cctype> using namespace std; const int N = 3000001; int _, f[21][N], __, dep[N]; inline char Nc() { static char Buf[100000], *p1, *p2; return p1==p2&&(p2=(p1=Buf)+fread(Buf, 1, 100000, stdin), p1==p2)?EOF:*p1++; } int Rd() { int x = 0; /*scanf("%d", &x); return x;*/char c = Nc(); while(!isdigit(c)) c=Nc(); while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=Nc(); return x; } char Gc() { char c = Nc(); while(isspace(c)) c = Nc(); return c; /*char c[3]; scanf("%s", c); return c[0];*/ } int lca(int x, int y) { if(dep[y] < dep[x]) swap(x, y); for(int i=20;i>=0;i--) { if(dep[x] <= dep[y] - (1<<i)) y = f[i][y]; } if(x==y)return x; for(int i=20;i>=0;i--) { if(f[i][x] == f[i][y]) continue; x = f[i][x], y = f[i][y]; } return f[0][x]; } int main() { int t = Rd(); __ = 1; while(t--) { dep[1] = 1; char opt = Gc(); if(opt=='A') { int fa = Rd(); __++; dep[__] = dep[fa]+1; f[0][__] = fa; for(int i=1;i<=20;i++) { f[i][__] = f[i-1][f[i-1][__]]; } } else { int k = Rd(); k--; int x, y; x = Rd(); while(k--) { y = Rd(); if(x!=1) x = lca(x, y); } printf("%d\n", x); } } }