题目

最近公共祖先

分析

 
    求区间最小值,使用RMQ_ST算法。

实现

#include<iostream>
#include<string.h>
#include<queue>
#include<cmath>
#include<unordered_map>
#include<unordered_set>
#include<string>
#include<vector>
using namespace std;
const int inf = 1 << 29;
const int kMax = 200005;
unordered_map<string, int> gName2node;
unordered_map<int, string> gNode2name;
int gVisitNode[2 * kMax];	//按照访问次序,节点的排列
int gVisitDepth[2 * kMax];	//按照访问次序,节点的深度
int gNodeLastVisitSeq[kMax]; //节点最后一次被访问的序号
int dp[2*kMax][21][2];
struct Edge{
	int to;
	int next;
};
Edge gEdges[kMax];
int gEdgeIndex;
int gHead[kMax];

//从根节点出发,按照dfs方式遍历整个树,将每一步遍历到的节点放到 visit_seq 中
void Dfs(int node, int& cur_seq, int depth){
	gVisitDepth[cur_seq] = depth; //记录当前深度,用于后续的区间最小查询
	gNodeLastVisitSeq[node] =  cur_seq;
	gVisitNode[cur_seq++] = node; //进入node节点
	for (int e = gHead[node]; e != -1; e = gEdges[e].next){
		int v = gEdges[e].to;
		Dfs(v, cur_seq, depth+1);
		gVisitDepth[cur_seq] = depth;
		gNodeLastVisitSeq[node] = cur_seq;
		gVisitNode[cur_seq++] = node; //离开node节点
	}
}


void InsertEdge(int u, int v){
	int e = gEdgeIndex++;
	gEdges[e].to = v;
	gEdges[e].next = gHead[u];
	gHead[u] = e;
}

void Init(int n){
	gEdgeIndex = 0;
	memset(gEdges, -1, sizeof(gEdges));
	memset(gHead, -1, sizeof(gHead));
	memset(dp, 0, sizeof(dp));
}

void AddPerson(string person){
	if (gName2node.find(person) == gName2node.end()){
		int node = gName2node.size();
		gName2node[person] = node;
		gNode2name[node] = person;
	}
}
inline int min(int a, int b){
	return a < b ? a : b;
}
int main(){
	int n, n1, n2;
	string person1, person2;
	cin >> n;
	Init(n);
	for (int i = 0; i < n; i++){
		cin >> person1 >> person2;
		AddPerson(person1);
		AddPerson(person2);
		n1 = gName2node[person1];
		n2 = gName2node[person2];
		InsertEdge(n1, n2);
	}
	int cur_seq = 0;
	Dfs(0, cur_seq, 0);
	//树的遍历形成的数组,长度为cur_seq
	for (int i = 1; i <= cur_seq; i++){
		dp[i][0][0] = gVisitDepth[i - 1];
		dp[i][0][1] = gVisitNode[i - 1];
	}
	for (int j = 0; j <= 20; j++){
		dp[0][j][0] = inf;
	}
	int len = log2(cur_seq);
	for (int j = 1; j <= len; j++){
		for (int i = 1; i + (1 << j) - 1 <= cur_seq; i++){
			if (dp[i][j - 1][0] < dp[i + (1 << (j - 1))][j - 1][0]){
				dp[i][j][0] = dp[i][j - 1][0];
				dp[i][j][1] = dp[i][j - 1][1];
			}
			else{
				dp[i][j][0] = dp[i + (1 << j - 1)][j - 1][0];
				dp[i][j][1] = dp[i + (1 << j - 1)][j - 1][1];
			}
		}
	}
	int m;
	cin >> m;
	for (int i = 0; i < m; i++){
		cin >> person1 >> person2;
		n1 = gNodeLastVisitSeq[gName2node[person1]] + 1;
		n2 = gNodeLastVisitSeq[gName2node[person2]] + 1;
		if (n1 > n2)
			swap(n1, n2);
		int k = log2(n2 - n1 + 1);
		int min_depth_node;
		if (dp[n1][k][0] < dp[n2 - (1 << k) + 1][k][0]){
			min_depth_node = dp[n1][k][1];
		}
		else{
			min_depth_node = dp[n2 - (1 << k) + 1][k][1];
		}
		cout << gNode2name[min_depth_node] << endl;
	}
	return 0;
}

 

相关文章:

  • 2021-09-08
  • 2021-07-19
  • 2021-09-25
  • 2022-02-02
  • 2021-10-17
  • 2021-08-02
猜你喜欢
  • 2021-11-11
相关资源
相似解决方案