• (待填坑)【数据结构】笛卡尔树


    知识点

    一 . 笛卡尔树 Cartesian Tree

    笛卡尔树中的节点及元素满足以下两个性质:

    ① 树中的元素满足二叉搜索树性质,要求按照中序遍历得到的序列为原数组序列

    ② 树中节点满足性质,根节点的值要大于其左右子节点的值

    二 . 四毛子算法 Method of Four Russians

    (待填坑)


    模板题 

    洛谷 P5854 【模板】笛卡尔树

    题目描述

    给定一个 1 \sim n 的排列 p,构建其笛卡尔树。

    即构建一棵二叉树,满足:

    1. 每个节点的编号满足二叉搜索树的性质。
    2. 节点 i 的权值为 p_i,每个节点的权值满足小根堆的性质。

    输入格式

    第一行一个整数 n。

    第二行一个排列 p_{1 \dots n}​。

    输出格式

    设 l_i,r_i 分别表示节点 i 的左右儿子的编号(若不存在则为 0)。

    一行两个整数,分别表示 \operatorname{xor}_{i = 1}^n i \times (l_i + 1) 和 \operatorname{xor}_{i = 1}^n i \times (r_i + 1)

    输入输出样例

    输入 #1

    5
    4 1 3 2 5
    

    输出 #1

    19 21
    

    说明/提示

    【样例解释】

    il_ir_i
    100
    214
    300
    435
    500

    【数据范围】

    对于 30% 的数据,n \leqslant 10^3

    对于 60% 的数据,n \leqslant 10^5

    对于 80% 的数据,n \leqslant 10^6

    对于 90% 的数据,n \leqslant 5 \times 10^6

    对于 100% 的数据,1 \leqslant n \leqslant 10^7

     (待填坑)

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #define ll long long
    7. #define re register
    8. using namespace std;
    9. int n,top=0,k=0;
    10. ll int L,R;
    11. const int maxn=1e7+5,INF=0x3f3f3f3f;
    12. int a[maxn],left_tree[maxn],right_tree[maxn],s[maxn];
    13. inline int read()
    14. {
    15. int x=0,f=1;
    16. char c=getchar();
    17. while(c<'0'||c>'9')
    18. {
    19. if(c=='-') f=-1;
    20. c=getchar();
    21. }
    22. while(c>='0'&&c<='9')
    23. {
    24. x=(x<<1)+(x<<3)+(c^48);
    25. c=getchar();
    26. }
    27. return x*f;
    28. }
    29. inline void make_tree(int l,int r) //使用单调栈维护建树
    30. {
    31. for(re int i=l;i<=r;++i)
    32. {
    33. k=top;
    34. while(k&&a[s[k]]>a[i]) k--;
    35. if(k) right_tree[s[k]] =i;
    36. if(k1];
    37. s[++k]=i;
    38. top=k;
    39. }
    40. }
    41. int main()
    42. {
    43. n=read();
    44. for(re int i=1;i<=n;++i)
    45. {
    46. a[i]=read();
    47. }
    48. make_tree(1,n);
    49. for(re int i=1;i<=n;++i)
    50. {
    51. L^=1ll*i*(left_tree[i]+1); //要转换成long long形式
    52. R^=1ll*i*(right_tree[i]+1);
    53. }
    54. printf("%lld %lld",L,R);
    55. return 0;
    56. }

     相关练习

    1 . 洛谷 P3793 由乃救爷爷

    思路:题目很长,但有用的信息缩减得:有n(n\leqslant2\times10^7)个数,m(m\leqslant2\times10^7)个询问,每次询问问区间[l,r]中的最大值。可以用笛卡尔树求RMQ最值。

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. /****随机数生成器,题目已给出****/
    7. namespace GenHelper
    8. {
    9. unsigned z1,z2,z3,z4,b;
    10. unsigned rand_()
    11. {
    12. b=((z1<<6)^z1)>>13;
    13. z1=((z1&4294967294U)<<18)^b;
    14. b=((z2<<2)^z2)>>27;
    15. z2=((z2&4294967288U)<<2)^b;
    16. b=((z3<<13)^z3)>>21;
    17. z3=((z3&4294967280U)<<7)^b;
    18. b=((z4<<3)^z4)>>12;
    19. z4=((z4&4294967168U)<<13)^b;
    20. return (z1^z2^z3^z4);
    21. }
    22. }
    23. void srand(unsigned x)
    24. {using namespace GenHelper;
    25. z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51;}
    26. int read()
    27. {
    28. using namespace GenHelper;
    29. int a=rand_()&32767;
    30. int b=rand_()&32767;
    31. return a*32768+b;
    32. }
    33. /***构造笛卡尔树及查询函数***/
    34. int n,m,s;
    35. const int maxn=20000005;
    36. int a[maxn],ltree[maxn],rtree[maxn],st[105];
    37. int query(int l,int r) //找到当前区间的最大值
    38. {
    39. int rt=st[1];
    40. for(;;)
    41. {
    42. if(l<=rt && rt<=r) return a[rt];
    43. if(rt
    44. else rt=ltree[rt];
    45. }
    46. }
    47. void make_tree() //笛卡尔树有两种写法
    48. {
    49. int top=0;
    50. for(int i=1;i<=n;++i)
    51. {
    52. int k=0;
    53. while(top&&a[st[top]]<=a[i]) k=st[top--];
    54. ltree[i]=k;
    55. if(top) rtree[st[top]]=i;
    56. st[++top]=i;
    57. }
    58. }
    59. int main()
    60. {
    61. cin>>n>>m>>s;
    62. srand(s);
    63. for(int i=1;i<=n;++i)
    64. {
    65. a[i]=read();
    66. }
    67. make_tree();
    68. unsigned long long ans=0;
    69. int l,r;
    70. for(int i=1;i<=m;++i)
    71. {
    72. l=read()%n+1; r=read()%n+1;
    73. if(l>r) swap(l,r);
    74. ans+=query(l,r);
    75. }
    76. cout<
    77. return 0;
    78. }

    2 .  洛谷 P1377 [TJOI2011] 树的序

    思路:由题得:给一个生成序列,建出一棵笛卡尔树,求字典序最小的可以得到相同笛卡尔树的生成序列,最后进行笛卡尔树的先序遍历。

    进行先序遍历的原因:根据二叉搜索树的性质,其先序的字典序最小,先要确认根节点的位置,再确认左子树,最后确认右子树

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int n,k=0,top=0;
    7. const int maxn=1e7+5;
    8. int a[maxn],st[maxn],ltree[maxn],rtree[maxn];
    9. inline int read()
    10. {
    11. int x=0,f=1;
    12. char c=getchar();
    13. while(c<'0'||c>'9')
    14. {
    15. if(c=='-') f=-1;
    16. c=getchar();
    17. }
    18. while(c>='0'&&c<='9')
    19. {
    20. x=(x<<1)+(x<<3)+(c^48);
    21. c=getchar();
    22. }
    23. return x*f;
    24. }
    25. inline void dfs(int x)
    26. {
    27. if(x!=0)
    28. {
    29. printf("%d ",x); //输出根节点后进行左右子树的查找
    30. dfs(ltree[x]);
    31. dfs(rtree[x]);
    32. }
    33. }
    34. int main()
    35. {
    36. n=read();
    37. for(int i=1;i<=n;++i)
    38. {
    39. int x=read();
    40. a[x]=i; //转换成输入的值的序号进行建树
    41. }
    42. for(int i=1;i<=n;++i)
    43. {
    44. k=top;
    45. while(k && a[st[k]]>a[i]) k--;
    46. if(k) rtree[st[k]]=i;
    47. if(k1];
    48. st[++k]=i;
    49. top=k;
    50. }
    51. dfs(st[1]); //从根开始搜索
    52. return 0;
    53. }

  • 相关阅读:
    C# XML序列化与反序列化记录
    【软件逆向】如何在windows下远程注入dll并进行虚表hook
    搜维尔科技:【软件篇】TechViz是一款专为工程设计的专业级3D可视化软件
    Selenium结合Jenkins进行持续集成
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    使用java连接数据库报错:Exception in thread “main“ com.mysql.cj.jdbc.exceptions.
    Vue框架--Vue中的数据代理
    NAND闪存市场彻底复苏
    掌握区块链浏览器的使用,应该是每一个币圈人的必修课。
    汽车智能座舱/智能驾驶SOC -2
  • 原文地址:https://blog.csdn.net/gzkeylucky/article/details/126750089