//log2(n)函数在头文件cmath中,得以2为底n的对数 for(int i = log2(n); i >= 0; --i){ int _x = st[x][i];//在当前i下x和y跳到的位置 int _y = st[y][i]; if(_x == _y)continue;//当x和y跳到的位置相同,说明跳过了,x和y不更新 x = _x;//更新以二分逼近x和y的最近公共祖先的子节点 y = _y; } return root[x];
#include<iostream> #include<vector> #include<cstdio> #include<cmath> #define int long long usingnamespace std; constint N = 1e6; vector<int> mp[N]; int n, m; int dep[N], root[N], st[N][20]; /* 调用函数时,传入根节点,显然根节点并没有父节点,所以_root可以传入0 形如 init_root(1, 0); 之后在计算dep[N]数组的时候不用特判,直接在dep[0]的基础上加1,深度就是1(当然你的dep[0]需要初始化) */ voidinit_root(int x, int _root){//x代表当前节点,_root代表当前节点的父节点 root[x] = _root;//存储x点的父节点 dep[x] = dep[_root]+1;//存储x点的深度 for(int i = 0; i < mp[x].size(); ++i){//dfs int y = mp[x][i]; if(y == _root)continue;//不能往回走 init_root(y, x);//下一个点 } }
voidinit_st(){ for(int i = 1; i <= n; ++i){ st[i][0] = root[i];//st表的初始状态:i走(1<<0)到的是i的父节点 }
intlca(int x, int y){ if(dep[x] < dep[y])swap(x, y); int len = dep[x]-dep[y];//按位取位权 int i = 0;//第几位 while(len != 0){//使得x, y深度相同 建议脑子里换成二进制理解 if(len%2 == 1){//当前位置存在1 x = st[x][i];//向上走 } len /= 2;//或者右移 (len>>1); i++; } if(x == y)return x;//如果这个时候x == y就说明x和y在同一棵子树,没必要进行下一步了。 //log2(n)函数在头文件cmath中,得以2为底n的对数 for(int i = log2(n); i >= 0; --i){ int _x = st[x][i];//在当前i下x和y跳到的位置 int _y = st[y][i]; if(_x == _y)continue;//当x和y跳到的位置相同,说明跳过了,x和y不更新 x = _x;//更新以二分逼近x和y的最近公共祖先的子节点 y = _y; } return root[x]; }
signedmain(){ cin >> n >> m; for(int i = 1; i <= n; ++i){ int x, y; cin >> x >> y; mp[x].push_back(y); } init_root(1, 0); init_st(); for(int i = 1; i <= m; ++i){ int x, y; cin >> x >> y; cout << lca(x, y) << endl; } return0; }