hdu 4409 Family Name List

本文介绍了一种用于构建和查询家族树的算法,通过预处理实现快速查询最近公共祖先及节点信息。利用map存储成员名字,确保名字按字母顺序排列,并通过构建家族树进行父子关系连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 Three operations
 	L     : the same as input, correspond to Preorder traversal.
 	b x   : correspond to ask how many sons does x's father have.
 	c x y : LCA(x, y), there is a trick, if LCA(x, y) is x or y,
		    you should output LCA(x, y)'s father,
		    because in our real life, one can't be one's ancestor.

 About sorting the brothers
 	We can use map to store their names.
	Then their names will be in alphabetical order.
	At last, Scan the map and construct the family tree.
 */
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <map>
using namespace std;
//STL
#define MS(c, a) memset(c, a, sizeof c)
//Syntax
#define Rep(c, a, b) for (int c = (a); c < (b); c++)
//Constant
const int MAXN = 30005 << 1;
//Array
typedef int AI[MAXN];

//FSG
struct Edge{
    int v, next;
};
vector<Edge> E;
AI L;
void G_ini(){
	E.clear(); MS(L, -1);
}
void AE(int u, int v){
	Edge te = {v, L[u]};
	L[u] = E.size();
	E.push_back(te);
}
#define Ere(c, a, L) for (int c = L[a]; c != -1; c = E[c].next)

//RMQ
int  ind;
AI dep, ta, id, st[20];
void TTI(int u, int fa = -1)
{
	if (fa != -1) dep[u] = dep[fa] + 1;
	id[u] = ind;
	ta[ind++] = u;
	for (int i = L[u]; i != -1; i = E[i].next)
		if (E[i].v != fa)
		{
			TTI(E[i].v, u);
			ta[ind++] = u;
		}
}
int low(int x)
{
	int o = 0;
	while ((1 << o) <= x) o++;
	return o;
}
void st_ini()
{
	Rep(i, 0, ind) st[0][i] = ta[i];
	int l = low(ind);
	Rep(i, 1, l) Rep(j, 0, ind)
		if (j + (1 << i) < ind)
		{
			int x = st[i - 1][j],
				y = st[i - 1][j + (1 << (i - 1))];
			st[i][j] = (dep[x] < dep[y])? x: y;
		}
}
int rmq(int x, int y)
{
	x = id[x];
	y = id[y];
	if (x > y) swap(x, y);
	int l = low(y - x + 1) - 1;
	x = st[l][x];
	y = st[l][y - (1 << l) + 1];
	return (dep[x] < dep[y])? x: y;
}

int n, q;
AI fat, now, son;
char buf[MAXN];
string nam[MAXN];
map<string, int> H;
map<string, int>::reverse_iterator Hi; 

void LT(int u, int d = 0)
{
	Rep(i, 0, d) putchar('.');
	printf("%s\n", nam[u].c_str());
	Ere(i, u, L) LT(E[i].v, d + 1);
}

int main()
{
	while (scanf("%d", &n), n)
	{
		MS(fat, -1);
		MS(now, -1);
		MS(son, 0);
		H.clear();
		scanf("%s", buf);
		string ne = buf;
		H[ne] = 1;
		nam[now[0] = 0] = ne;
		Rep(i, 2, n + 1)
		{
			scanf("%s", buf);
			int k = 0;
			while (buf[k] == '.') k++;
			son[fat[i - 1] = now[k - 1]]++; 
			H[ne = buf + k] = i;
			nam[now[k] = i - 1] = ne;
		}
		G_ini();
		for (Hi = H.rbegin(); Hi != H.rend(); Hi++)
		{
			int v = Hi->second - 1, u = fat[v];
			if (Hi->second > 1) AE(u, v);
		}
		MS(dep, 0);
		TTI(ind = 0);
		st_ini();
		scanf("%d", &q);
		while (q--)
		{
			char op[3];
			scanf("%s", op);
			if (op[0] == 'L') LT(0);
			if (op[0] == 'b')
			{
				scanf("%s", buf);
				ne = buf;
				int u = H[ne] - 1;
				if (!u) puts("1");
				else printf("%d\n", son[fat[u]]);
			}
			if (op[0] == 'c')
			{
				scanf("%s", buf);
				ne = buf;
				int u = H[ne] - 1;
				scanf("%s", buf);
				ne = buf;
				int v = H[ne] - 1, p = rmq(u, v);
				if (p == u || p == v) p = fat[p];
				printf("%s\n", nam[p].c_str());
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值