【笔记】笛卡尔树

一个序列的笛卡尔树,中序是原序列,每个点是子树最值
性质:[l, r] 区间最值等于树上 lca(l, r) 的权值(l、r 分别属于 lca(l, r) 的左右子树!)
(考虑这个 x=lca(l, r), 显然序列上其左边的一段点在其左子树,右边一段在其右子树,所以其就是这些 l 和 r 的区间最值)

#include <stack>
#include <cstdio>
using namespace std;
const int MAXN = 10000007;
int N, A[MAXN], ls[MAXN], rs[MAXN];
int rot=1;
stack<int> S;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
int read()
{
	register int o = 0;
	register char c = getchar();
	while (c< '0' || c> '9') c = getchar();
	while (c>='0' && c<='9') o = (o<<3)+(o<<1)+(c&15), c = getchar();
	return o;
}
int main()
{
	scanf("%d", &N); for (int i=1; i<=N; i++) A[i] = read();
	S.push(1);
	for (int i=2; i<=N; i++) {
		int lst = 0;
		while (!S.empty() && A[S.top()]> A[i]) lst = S.top(), S.pop();
		ls[i] = lst;
		if (S.empty()) rot = i; else rs[S.top()] = i;
		S.push(i);
	} 
	long long ansl = 0, ansr = 0;
	for (int i=1; i<=N; i++) ansl^=1ll*i*(ls[i]+1),ansr^=1ll*i*(rs[i]+1);
	printf("%lld %lld\n", ansl, ansr);
}

比之前ST表查找要少一个log的时间和空间

CF1156E Special Segments of Permutation
笛卡尔树上做 dsu on tree

posted @ 2021-11-10 18:33  zrkc  阅读(41)  评论(0)    收藏  举报