码迷,mamicode.com
首页 > 其他好文 > 详细

模板 - 笛卡尔树

时间:2019-08-10 09:31:46      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:define   pre   --   include   end   ons   printf   def   namespace   

#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));
    }
}

模板 - 笛卡尔树

标签:define   pre   --   include   end   ons   printf   def   namespace   

原文地址:https://www.cnblogs.com/Yinku/p/11330330.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!