码迷,mamicode.com
首页 > 其他好文 > 详细

[hiho 17]最近公共祖先 三

时间:2015-05-09 23:18:38      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

题目描述

这次是使用在线算法解决这个问题。

两个节点的最近公共祖先就是这两个节点的通路上深度最浅的那个节点。

可以通过一遍深搜把树转成数组:每次经过一个节点(无论是从父节点进入还是从子节点返回)时,把它放入数组。同时要记录每个节点在数组中最后一次出现的位置。

使用RMQ-ST算法预先计算2^k长度区间内深度最浅的节点编号。

对于每次询问,将其转换为两个区间段求解。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

#define MAX 100005
#define MAX_HASH  200005

using namespace std;

char names[MAX_HASH][50];

vector<int> sons[MAX_HASH];
int last_occurance[MAX_HASH];
int dpth[MAX_HASH];

int data[MAX * 2][25];
int idx, n, q;

unsigned int BKDRHash(char *str)
{
    unsigned int seed = 131;
    unsigned int hash = 0;

    while (*str)
    {
        hash = hash * seed + (*str++);
    }

    return (hash & 0x7FFFFFFF) % MAX_HASH;
}

int get_index(char *str) {
	int res = BKDRHash(str);
	while (strlen(names[res]) != 0 && strcmp(str, names[res])) {
		res++;
		if (res > MAX_HASH) res -= MAX_HASH;
	}
	if (strlen(names[res]) == 0) {
		strcpy(names[res], str);
	}
	return res;
}

void dfs(int root_idx, int depth) {
	dpth[root_idx] = depth;
	/*cout << names[root_idx] << depth << endl;*/
	data[idx][0] = root_idx;
	last_occurance[root_idx] = idx;
	idx++;

	int sons_len = sons[root_idx].size();
	for (int i = 0; i < sons_len; i++) {
		dfs(sons[root_idx][i], depth + 1);
		data[idx][0] = root_idx;
		last_occurance[root_idx] = idx;
		idx++;
	}
}

void pre_calc() {
	//for (int i = 0; i < idx; i++) {
	//	cout << i << ":" << names[data[i][0]] << endl;
	//}
	int t = idx;
	int x = 0;
	while (t) {
		x++;
		t >>= 1;
	}
	x--;
	for (int i = 1; i <= x; i++) {
		for (int j = 0; j <= idx - (1 << i); j++) {
			data[j][i] = dpth[data[j][i - 1]] < dpth[data[j + (1 << (i - 1))][i - 1]] ? data[j][i - 1] : data[j + (1 << (i - 1))][i - 1];
			//cout << j << ‘-‘ << j + (1 << i) - 1 <<‘:‘ << names[data[j][i]] << endl;
		}
	}
}

int main() {
	char s1[50], s2[50];
	int i1, i2;
	int start;

	cin >> n;
	cin >> s1 >> s2;
	i1 = get_index(s1);
	i2 = get_index(s2);
	sons[i1].push_back(i2);
	start = i1;
	while (--n) {
		cin >> s1 >> s2;
		i1 = get_index(s1);
		i2 = get_index(s2);
		sons[i1].push_back(i2);
	}

	dfs(start, 0);
	pre_calc();
	
	cin >> q;
	while(q--) {
		cin >> s1 >> s2;
		i1 = last_occurance[get_index(s1)];
		i2 = last_occurance[get_index(s2)];
		if (i1 > i2) {
			int t = i1;
			i1 = i2;
			i2 = t;
		}
		int len = i2 - i1 + 1;
		int x = 0;
		while (len) {
			x++;
			len >>= 1;
		}
		x--;
		len = 1 << x;
		cout << names[dpth[data[i1][x]] < dpth[data[i2 - len + 1][x]] ? data[i1][x] : data[i2 - len + 1][x]] << endl;
	}
	return 0;
}

[hiho 17]最近公共祖先 三

标签:

原文地址:http://www.cnblogs.com/xblade/p/4491251.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!