多亏了大佬给我讲题我才可以写出来,记录一下!!!!
题目:
#include<iostream>
#include<vector>
using namespace std;
const long long N = 1e5 + 7;
long long n, q;
long long h[N];
long long stack[N];//单调栈
vector<long long>g[N];
long long d[N]={0};//深度 || 入度
long long f[N][21];
//u: 儿子
//p: 父亲
void dfs(long long u, long long p) {
//计算深度
d[u] = d[p] + 1;
f[u][0] = p;
for (int i = 0; i < g[u].size(); i++) {
dfs(g[u][i], u);
}
}
void init() {
//f[j][i] : 表示 第 j 个节点 的 2^i 的父亲 下标
for (int i = 1; i < 21; i++) {
for (int j = 1; j <= n; j++) {
f[j][i] = f[f[j][i - 1]][i-1];
}
}
}
int lca(long long x,long long y) {
if (f[x][20] != f[y][20]) {//不在一个联通树上
return -1;
}
if (d[x] > d[y])swap(x, y);//x 的深度<= y
//x y 要到同一层
for(long long i = 20;i>=0;i--){
if (d[f[y][i]] >= d[x]) {
//说明y可以跳到f[y][i] 这个点上面 不会小于 x 的深度
y = f[y][i];
}
}
if (y == x) {
//x 是 y 的父亲
if (f[x][0] == x) {//根节点
return -1;
}
return f[x][0];
}
//x !=y x 和 y 在两边
for (long long i = 20; i >= 0; i--) {
if (f[y][i] != f[x][i]) {
y = f[y][i];
x = f[x][i];
}
}
return f[x][0];
}
int main() {
cin >> n >> q;
long long i, j;
for (i = 1; i <= n; i++) {
cin >> h[i];
}
//建边
long long tt = 0;
for (i = 1; i <=n; i++) {
while (tt && h[stack[tt]] < h[i]) {
g[i].push_back(stack[tt]);
d[stack[tt]]++;//入度加一
tt--;
}
stack[++tt] = i;
}
//计算深度
for (i = 1; i <= n; i++) {
if (!d[i]) {//根节点
dfs(i, i);
}
}
//初始化 lca 数组
init();
long long x, y,temp;
while (q--) {
cin >> x >> y;
temp = lca(x, y);
if (temp == -1) {
cout << "0\n";
}
else {
cout << d[temp] << "\n";
}
}
return 0;
}