首页 > 其他分享 >笛卡尔树 (附洛谷模板题代码)

笛卡尔树 (附洛谷模板题代码)

时间:2024-12-20 19:42:10浏览次数:4  
标签:优先级 笛卡尔 Tree Treap 附洛谷 键值 rm 模板

前言

打了一场 \(\rm{codeforces}\) , 其中 F 使用了笛卡尔树, 看起来这个东西的优先级比矩快还高, 那就学一下

似乎这道题并没有使用很多笛卡尔树的性质, 但是 \(\rm{yishu2}\) 开了个专题, 这下不得不学了

笛卡尔树

之前预习的时候看了一下

首先复习一下二叉查找树的性质

  • 每个节点拥有用于比较大小的键值
  • 对于任意一个节点, 令 \(Val_i\) 表示 \(i\) 点的键值, 有 \(Val_{rightson} >(\geq) Val_{fa} >(\geq) Val_{leftson}\)
  • 由上可知, 二叉查找树的中序排列为有序数组

然后我们知道的是, \(\rm{Treap}\) 这样一个数据结构, 即 "树堆" , 基于 "键值 + 优先级" 这样的方式来维护二叉树的平衡性, 再具体一点, 我们知道对于键值, \(\rm{Treap}\) 是一颗二叉查找树, 而对于优先级, \(\rm{Treap}\) 是一个堆

\(\rm{Treap}\) 具体如何保证二叉树的平衡性虽然不是现在最主要的部分, 但为了了解深一点, 我在这里同时介绍一下

关于笛卡尔树的前置 : \(\rm{Treap}\)

\(\rm{Treap}\) 树有一个很棒的性质, 即当每个节点的键值, 优先级确定且互不相同, 那么这样的一颗 \(\rm{Treap}\) 在形态上是确定唯一的, 书上用 \(x, y\) 坐标来解释

如何给定优先级, 使得 \(\rm{Treap}\) 平衡?

容易发现当随机给定优先级, 那么 \(\rm{Treap}\) 在期望上平衡

那么学都学了, 我们顺带也把插入键值不确定的新节点这一部分讲一讲, 这里只介绍旋转法

首先朴素插入键值, 然后用旋转法维护堆的性质不受影响, 余下的并不难理解

关于笛卡尔树

原理 \(\And\) 特性

当每个数的键值预先确定, 那么这就是笛卡尔树

常见的, 笛卡尔树主要用于处理一个确定的数列, 把位置看做键值, 把数值看做优先级, 笛卡尔树有如下性质

  • 当你对笛卡尔树做中序遍历, 那么返回的结果就是原数列, 这个可以用划线法来理解, 这里不加赘述
  • 如果按照大根堆来建树, 那么根节点的数值一定大于其子树中所有节点

建立笛卡尔树

你说的对, 但是如果你使用 \(\rm{Treap}\) 的方法建立笛卡尔树, 不仅会带来巨大的码量, 而且多出了一个 \(\log\) , 这不好

所以介绍单调栈 \(\mathcal{O} (n)\) 的建树, 具体怎么推得我不加阐述了, 只介绍做法

每次插入新的节点 (先按照键值排序, 只需要按照优先级调整上下位置), 其横向位置一定, 一定是在最右边, 我们只需要考虑最右链

我们用单调栈维护最右链, 这样每次插入的时候, 新儿子一定在最右链的末端

单调栈可以找到最右链中, 第一个优先级比插入点高的点, 记为 \(u\) (若没有, 代码中设计了一个虚根 \(0\), 其优先级为 \(+\infty\)) , 以及这个点原本的右儿子 (只会影响到右儿子, 因为处理的是最右链) , 那么这个点将霸占 \(u\) 的右儿子位置, 并且原来的点将成为这个点的左儿子

思路

正式进入这道题, 他要求按照小根堆来建树, 那么我们只需要在建树的时候, 把优先级的比较改一下即可

实现

#include "bits/stdc++.h"
const int MAXN = 1e7 + 20;
const int INF = 0x3f3f3f3f;
typedef long long ll;

namespace IO
{
    inline int read() {
        int f = 1, x = 0;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
            x = x * 10 + (ch - '0'), ch = getchar();
        return x * f;
    }
};
using namespace IO;

int n;

/*笛卡尔树*/
struct Cartesian_Tree
{
    struct node {
        int ls, rs, fa; // 位置信息
        int pri, key; // 优先级 & 键值

        bool operator < (const node& a) {
            return key < a.key;
        }
    } Tree[MAXN];

    /*建树*/
    void buildtree() {
        std::stack<int> MS; MS.push(0);
        for (int i = 1; i <= n; i++) {
            int pos = MS.top();
            while (!MS.empty() && Tree[pos].pri > Tree[i].pri) {
                pos = Tree[MS.top()].fa;
                MS.pop();
            }

            Tree[i].ls = Tree[pos].rs, Tree[Tree[i].ls].fa = i, Tree[pos].rs = i, Tree[i].fa = pos;
            MS.push(i);
        }
    }
} C_Tree;

/*计算题目要求的答案*/
void calc()
{
    ll ans1, ans2;
    for (ll i = 1; i <= n; i++) {
        ans1 = ((i == 1) ? i * (C_Tree.Tree[i].ls + 1ll) : (i * (C_Tree.Tree[i].ls + 1ll)) ^ ans1);
        ans2 = ((i == 1) ? i * (C_Tree.Tree[i].rs + 1) : (i * (C_Tree.Tree[i].rs + 1)) ^ ans2);
    }
    printf("%lld %lld", ans1, ans2);
}

int main()
{
    n = read();
    for (int i = 1; i <= n; i++)
        C_Tree.Tree[i].key = i, C_Tree.Tree[i].pri = read();
    C_Tree.Tree[0].fa = C_Tree.Tree[0].ls = C_Tree.Tree[0].rs = C_Tree.Tree[0].key = 0;
    C_Tree.Tree[0].pri = INF;

    /*对标签排序 (本题中不需要)*/
    // std::sort(C_Tree.Tree + 1, C_Tree.Tree + n + 1);

    C_Tree.buildtree();

    calc();

    return 0;
}

标签:优先级,笛卡尔,Tree,Treap,附洛谷,键值,rm,模板
From: https://www.cnblogs.com/YzaCsp/p/18619885

相关文章

  • Origin绘图教程 | 创建模板与批量绘图
    主要内容:创建图形模板+批量绘图图形模板 请打开在我们在第一课:我的第一张绘图中保存的项目文件。点选图形窗口。可以通过菜单列表文件:近期项目来快速打开最近保存过的项目文件。 1.双击坐标刻度线标签,打开坐标轴对话框。 2.按住Ctrl键并选中对话框左边的上轴和右轴图标......
  • 实验6 模板类、文件I/O和异常处理
    1.实验任务4Vector.hpp1#pragmaonce2#include<iostream>3#include<stdexcept>45usingnamespacestd;67template<typenameT>8classVector{9public:10Vector(intn);11Vector(intn,Tvalue);12Vector(co......
  • P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并
    [Vani有约会]雨天的尾巴/【模板】线段树合并题目背景深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。无......
  • 实验6 模板类、文件I/O和异常处理
    实验任务4:Vector.hpp源码:1#pragmaonce2#include<iostream>3#include<stdexcept>4usingnamespacestd;56template<typenameT>7classVector{8public:9Vector(intn):size(n)10{11if(n<0)12......
  • 可以直接使用模板搭建虚拟展厅么?
    可以直接使用模板搭建虚拟展厅。以下是对这一方式的详细解释:一、模板搭建的可行性许多虚拟展厅搭建平台都提供了丰富的模板供用户选择。比如视创云展平台,就拥有海量展厅模板,适合多种行业使用。这些模板通常已经包含了基本的展厅结构和布局,用户只需在此基础上进行个性化调整,如......
  • 怎么修改网站底部模板,如何更改网站底部的模板文件
    修改网站底部模板可以帮助您自定义网站的外观和功能。以下是详细的步骤:登录后台管理系统:打开浏览器,输入后台管理地址(如http://yourdomain.com/admin.php或http://yourdomain.com/wp-admin),使用管理员账号登录。导航到主题编辑页面:在后台左侧菜单中,找到“外观”或“主题......
  • 实验6 模板类、文件I/O与异常处理
    实验四vector.hpp#pragmaonce#include<iostream>#include<stdexcept>usingnamespacestd;template<typenameT>classVector{private:intsize;T*ptr;public:Vector(intsize,intvalue=0):size{size}{......
  • 实验六 模板类、文件I/O和异常处理
    1、实验任务一Complex.hpp#pragmaonce#include<iostream>#include<stdexcept>//声明//////////////////////////////////////////////////////复数模板类声明template<typenameT>classComplex{public:Complex(Tr=0,Ti=0);Complex(co......
  • 实验6 模板类、文件I/O和异常处理
    实验任务4:1#pragmaonce23#include<iostream>4#include<stdexcept>56usingnamespacestd;78template<typenameT>9classVector{10public:11Vector(intn,Tvalue=0);12~Vector();13Vec......
  • RealVNC旧版安装包及组策略模板下载方法
    msi安装包下载v6.2版本下载链接如下:https://downloads.realvnc.com/download/file/vnc.files/VNC-Server-6.2.0-Windows-msi.zip如需下载其他版本请替换下载链接中的VNC-Server-6.2.0-Windows为VNC-Server-x.x.x-Windows例如6.8.0版本:https://downloads.realvnc.com/downlo......