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);
}
}
}