最近公共祖先--RMQ

来源:互联网 发布:创意美工设计招聘 编辑:程序博客网 时间:2024/06/14 14:48

传送门:hihoCode.1069

#include <iostream>#include <string>#include <cstdio>#include <map>#include <vector>#include <cmath>#include<algorithm>using namespace std;const int maxn = 200005;int first[maxn];           //保存该人第一次访问出现的顺序int deep[2 * maxn];       //该点的深度int vex[2 * maxn];        //每个顺序表示的编号int dp[maxn][20];        //保存最近祖先的在数组中的下标,不能保存深度最小的,因为通过深度得不到该点数组下标,就不用说编号了map<string, int> mp;      //给每一个人赋值一个编号string name[maxn];      //用编号保存名字vector<int> vec[maxn];  //保存儿子int cnt = 0;            //编号用到 int k = 0;              //数组下标 void dfs(int x, int dep)     //得到数组 {vex[++k] = x;           //这里肯定访问的是新节点,因为for循环只会继续下一个未访问的节点 deep[k] = dep;first[x] = k;           //所以第一次访问肯定是这里 for (int i = 0; i < vec[x].size(); i++){dfs(vec[x][i], dep + 1);vex[++k] = x;       //访问儿子之后又访问自己 deep[k] = dep;}}void RMQ(){for (int i = 1; i <= k; i++)     //dp[i][j]保存的是深度最小的那一个的下标 {dp[i][0] = i;             //下标为i的数组往后1位深度最小的就是自己 }int a, b;for (int i = 1; i < 20; i++)      //20足够了 {for (int j = 1; j <= k; j++){if (j + (1 << i) - 1 <= k){a = dp[j][i - 1];b = dp[j + (1 << (i - 1))][i - 1];dp[j][i] = deep[a] > deep[b] ? b : a;   //得到深度最小的数组下标 }}}}void query(string name1, string name2)     //询问 {int b = max(first[mp[name1]], first[mp[name2]]);  //表示第一次访问的节点数组下标较大的一个 int a = min(first[mp[name1]], first[mp[name2]]);int k = log2(b - a + 1);                         //2的k次方可能不能包含b-a-1个数 int c = dp[a][k];int d = dp[b - (1 << k) + 1][k];int res = deep[c] > deep[d] ? d : c;             //得到深度最小的那一个的下标 cout<< name[vex[res]] << endl;                     //通过编号得到结果 }int solve(string s)             //给每一个字符串一个不同的编号,相当于不同的人 {if (mp.count(s) != 0){return mp[s];}name[++cnt] = s;            //通过编号保存人名 return mp[s] = cnt;}int main(){//freopen("Text.txt", "r", stdin);int ncase;string name1, name2;int m, n;int f, s;cin >> m;for (int i = 0; i < m; i++){cin >> name1 >> name2;f = solve(name1);s = solve(name2);vec[f].push_back(s);     //保存儿子 }dfs(1, 1);/*for (int j = 1; j <= k; j++)cout << vex[j] << " ";cout << endl;*/RMQ();cin >> n;while (n--){cin >> name1 >> name2;query(name1, name2);}return 0;}