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

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

 

posted @ 2018-06-30 16:26  TOBICHI_ORIGAMI  阅读(93)  评论(0编辑  收藏  举报