笛卡尔树
https://www.luogu.com.cn/problem/P5854
题意概述
给定一个排列 \(p\),构建其笛卡尔树,即:
-
每个节点编号满足二叉搜索树的性质。
-
每个节点的权值满足小根堆的性质。
思路
使用单调栈。对于节点 \(i\),先弹出单调栈中所有值大于 \(p_i\) 的,记录最后一个弹出的编号 \(last\)。如果栈非空,节点 \(i\) 成为栈顶元素的右孩子,如果栈顶元素已经有右孩子(\(last\) 不为 \(0\)),原本的右孩子成为 \(i\) 的左孩子;如果栈空,节点 \(i\) 成为头节点,此时原本的头节点(如果有)为 \(last\),成为 \(i\) 的左孩子。
时间复杂度 \(\mathcal{O}(n)\)。
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n;
cin >> n;
vector<int> p(n+1);
for (int i=1;i<=n;i++){
cin >> p[i];
}
stack<int> stk;
vector<int> left(n+1,-1),right(n+1,-1);
for (int i=1;i<=n;i++){
int last = -1;
while (!stk.empty() && p[i]<=p[stk.top()]){
last = stk.top();
stk.pop();
}
if (last!=-1){
left[i] = last;
}
if (!stk.empty()){
right[stk.top()] = i;
}
stk.push(i);
}
ll res1=0,res2=0;
for (int i=1;i<=n;i++){
res1^=(ll)i*((left[i]==-1?0:left[i])+1);
res2^=(ll)i*((right[i]==-1?0:right[i])+1);
}
cout << res1 << ' ' << res2 << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号