zoukankan      html  css  js  c++  java
  • 笛卡尔树

    笛卡尔树

    image-20200824215225144

    介绍

    笛卡尔树是形如上图的一棵树,满足

    ①堆的性质,如本图,小根堆,儿子的值大于等于父亲的值

    ②二叉搜索树性质,即左子树的点key(默认为下标)比根小,右子树的点key(默认为下标)比根大

    显然,按中序遍历这棵树,可得原序列

    和treap不同的是,树高不保证是log

    ③询问下标i到下标j之间(i<j)的最小值,只需寻找[i,j]的lca

    构建

    每次插入一个新节点时,为了确保二叉搜索树的性质得到满足(别忘了我们按照 key顺序插入),我们需要将新节点插入到尽可能靠右端的位置。

    我们维护最右链,同时,注意到最右链中val单调

    因此可以维护一个单调栈,来即时地找到插入位置

    模板

    #include <iostream>
    #include <utility>
    #include <cstdio>
    #include <cctype>
    using namespace std;
    const int N=1e7+5;
    inline int read() {
    	int x=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    int n,dat[N],st[N],ls[N],rs[N],top;
    inline void insert(int x) {
        while(top&&dat[st[top]]>dat[x]) top--;
        ls[x]=rs[st[top]],rs[st[top]]=x;
        st[++top]=x;
    }
    long long ans1,ans2;
    int main() {
        n=read();
        for(int i=1;i<=n;i++) dat[i]=read();
        for(int i=1;i<=n;i++) insert(i);
        for(int i=1;i<=n;i++) 
            ans1^=(i*(ls[i]+1ll)),ans2^=(i*(rs[i]+1ll));
        printf("%lld %lld
    ",ans1,ans2);
        return 0;
    }
    

    建树的方法2

    每次选取区间最大值作为根,然后往两边递归也可以建树

    直接暴力是O(n^2)

    线段树优化一下O(nlogn)

    树的序

    Description

    给一个生成序列,建出一棵笛卡尔树,求字典序最小的可以得到相同笛卡尔树的生成序列

    Solution

    按题意建好笛卡尔树之后输出先序遍历即可

    建树注意题目中的序列是模板中的key 序列,所以输入这里稍微转换一下

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N=100005; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,dat[N],st[N],top,ls[N],rs[N];
    void insert(int x) {
        while(top&&dat[st[top]]>dat[x]) top--;
        ls[x]=rs[st[top]];rs[st[top]]=x;
        st[++top]=x;
    }
    void dfs(int x) {
        if(!x) return;
        printf("%d ",x);
        dfs(ls[x]); 
        dfs(rs[x]);
    }
    int main() {
        n=read();
        for(int i=1,x;i<=n;i++) x=read(),dat[x]=i;
        for(int i=1;i<=n;i++) insert(i);
        dfs(st[1]);
        return 0;
    }
    

    Periodni ——题解https://www.luogu.com.cn/blog/Alansp/solution-sp3734

    https://www.luogu.com.cn/problem/P3246

    https://www.luogu.com.cn/problem/P5044

    https://www.luogu.com.cn/problem/P4755

    http://codeforces.com/problemset/problem/1117/G

    https://www.luogu.com.cn/problem/P2611

    参考文章:

    https://www.cnblogs.com/LiuRunky/p/Cartesian_Tree.html

    https://www.cnblogs.com/Miracevin/p/10373626.html

  • 相关阅读:
    操作数据库帮助类
    VS快捷键收藏
    sqlserver 定时任务
    LayUI相关
    java20140407
    java20140406
    java20140405
    获取一个字符串在整个字符串中出现的次数
    System类
    java中的集合Collection
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13574169.html
Copyright © 2011-2022 走看看