模板 - 笛卡尔树
Posted yinku
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板 - 笛卡尔树相关的知识,希望对你有一定的参考价值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(p) ch[p][0]
#define rs(p) ch[p][1]
const int MAXN = 100005;
int a[MAXN];
ll sum[MAXN], suf[MAXN];
int val[MAXN];
int ch[MAXN][2], siz[MAXN], tot, root;
inline void Init()
root = 0, tot = 0;
inline int NewNode(int v)
int p = ++tot;
ch[p][0] = ch[p][1] = 0;
val[p] = v;
siz[p] = 1;
return p;
inline void PushUp(int p)
siz[p] = siz[ls(p)] + siz[rs(p)] + 1;
//O(n)建树,返回新树的根
int st[MAXN], stop;
inline int Build(int n)
stop = 0;
for(int i = 1; i <= n; ++i)
//实际上笛卡尔树中tmp就是i
int tmp = NewNode(a[i]), last = 0;
//大根
while(stop && val[st[stop]] < val[tmp])
last = st[stop];
PushUp(last);
st[stop--] = 0;
if(stop)
rs(st[stop]) = tmp;
ls(tmp) = last;
st[++stop] = tmp;
while(stop)
PushUp(st[stop--]);
return st[1];
//[L,R]的最值下标
int Query(int root,int L,int R)
//笛卡尔树中节点下标=数组下标(从1开始)
while(root<L||root>R)
root=root<L?rs(root):ls(root);
return root;
ll CalcSum(int p)
if(!p)
return 0;
//p节点管辖的范围就是其左右子树,这道题里面要把根去掉
return CalcSum(ls(p)) + CalcSum(rs(p)) + 1ll * val[p] * ((siz[ls(p)]+1)*(siz[rs(p)]+1)-1);
int n;
int top;
int main()
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
while(~scanf("%d", &n))
Init();
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
root = Build(n);
printf("%lld\n", CalcSum(root));
以上是关于模板 - 笛卡尔树的主要内容,如果未能解决你的问题,请参考以下文章
luoguP4755 Beautiful Pair 笛卡尔树+线段树合并+启发式合并