整理.
笛卡尔树
给定一堆节点 $(k, w)$,要求构造一棵树,使得 $k$ 满足 bst 的性质,$w$ 满足堆的性质
即:给定一个数组,考虑一棵二叉树,每个节点都是所在子树的极值,中序遍历一棵树的顺序等于原区间的顺序
建树
- 用栈保存从根开始的右链,顺序插入每一个数
- 对于当前的树,从最右边的节点(栈顶)开始找到一个位置插入,并且把下面的链变成左儿子
考虑这个过程,不难理解,可以用维基百科上的图模拟一下
code
#include <bits/stdc++.h> using ll = long long; const int N = 10000010; int n, p[N], to[N]; int l[N], r[N]; inline char gc() { static const int N = 1 << 20; static char buf[N | 1], *S = buf, *T = buf; return S == T && (T = (S = buf) + fread(buf, 1, N, stdin), S == T) ? EOF : *S++; } template<typename T> inline void read(T &x) { x = 0; char ch = gc(); for (; ch < '0' || ch > '9';) ch = gc(); for (; ch <= '9' && ch >= '0';) x = x * 10 + (ch ^ 48), ch = gc(); } int main() { read(n); std::stack<int> st; for (int i = 1; i <= n; ++i) { read(p[i]), to[p[i]] = i; int las = -1; while (!st.empty() && st.top() > p[i]) las = st.top(), st.pop(); if (las != -1) l[i] = to[las]; if (!st.empty()) r[to[st.top()]] = i; st.push(p[i]); } ll _l = 0, _r = 0; for (int i = 1; i <= n; ++i) _l ^= 1ll * i * (l[i] + 1), _r ^= 1ll * i * (r[i] + 1); std::cout << _l << ' ' << _r << '\n'; return 0; }
|
洛谷上这题卡的有点变态了,,逼的我去更新了更快的板子,这份用的 Siyuan 的