NOWCODER141C:Shuffle Cards(FHQ Treap)

本文介绍了一种通过特定洗牌方式改变卡片顺序的算法,并使用C++中的Treap数据结构实现该算法。通过一系列操作,将指定区间的卡片移至顶部,最终得到新的卡片顺序。

题目描述 

Eddy likes to play cards game since there are always lots of randomness in the game. For most of the cards game, the very first step in the game is shuffling the cards. And, mostly the randomness in the game is from this step. However, Eddy doubts that if the shuffling is not done well, the order of the cards is predictable! 

To prove that, Eddy wants to shuffle cards and tries to predict the final order of the cards. Actually, Eddy knows only one way to shuffle cards that is taking some middle consecutive cards and put them on the top of rest. When shuffling cards, Eddy just keeps repeating this procedure. After several rounds, Eddy has lost the track of the order of cards and believes that the assumption he made is wrong. As Eddy's friend, you are watching him doing such foolish thing and easily memorizes all the moves he done. Now, you are going to tell Eddy the final order of cards as a magic to surprise him.

Eddy has showed you at first that the cards are number from 1 to N from top to bottom.

For example, there are 5 cards and Eddy has done 1 shuffling. He takes out 2-nd card from top to 4-th card from top(indexed from 1) and put them on the top of rest cards. Then, the final order of cards from top will be [2,3,4,1,5].

输入描述:

The first line contains two space-separated integer N, M indicating the number of cards and the number of shuffling Eddy has done.
Each of following M lines contains two space-separated integer pi, si indicating that Eddy takes pi-th card from top to (pi+si-1)-th card from top(indexed from 1) and put them on the top of rest cards.


1 ≤ N, M ≤ 105
1 ≤ pi ≤ N
1 ≤ si ≤ N-pi+1

输出描述:

Output one line contains N space-separated integers indicating the final order of the cards from top to bottom.

示例1

输入

复制

5 1
2 3

输出

复制

2 3 4 1 5

示例2

输入

复制

5 2
2 3
2 3

输出

复制

3 4 1 2 5

示例3

输入

复制

5 3
2 3
1 4
2 4

输出

复制

3 4 1 5 2

题意:N个数的数组初始分别是1~N,有M个操作,每个操作将一段区间移到数组开头,问最终数组是怎样的。

思路:这题最简单就是用C++封装好的容器rope,也可以写平衡树,比如无旋treap,treap就是堆和二叉搜索树的结合体,无旋treap就是没有旋转操作的treap,功能更强大。本题属于该数据结构的基本操作,将p下标的s个数移到开头,那么把树砍成三部分再连接起来就行。

# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline int Rand()
{
    static int seed=233;
    return seed=int(seed*48271LL%2147483647);
}
struct Treap
{
    Treap* son[2];
    int weight,sze,data;
    Treap(int v)
    {
        sze=1; data=v; weight=Rand();
        son[1] = son[0] = NULL;
        return;
    }
    inline void update()
    {
        sze = 1+(son[0]!=NULL?son[0]->sze:0)+(son[1]!=NULL?son[1]->sze:0);
        return;
    }
}*root;
typedef pair<Treap*,Treap*>D;
inline int sze(Treap* pos){return pos?pos->sze:0;}
Treap* merge(Treap* a,Treap* b)
{
    if(!a) return b;
    if(!b) return a;
    if(a->weight < b->weight)
    {
        a->son[1] = merge(a->son[1],b);
        a->update();
        return a;
    }else
    {
        b->son[0] = merge(a,b->son[0]);
        b->update();
        return b;
    }
}
D split(Treap* pos,int k)
{
    if(pos == NULL) return D(NULL,NULL);
    D y;
    if(sze(pos->son[0]) >= k)
    {
        y = split(pos->son[0],k);
        pos->son[0] = y.second;
        pos->update();
        y.second = pos;
    }
    else
    {
        y=split(pos->son[1],k-1-sze(pos->son[0]));
        pos->son[1] = y.first;
        pos->update();
        y.first = pos;
    }
    return y;
}
vector<int>ans;
void output(Treap* a)
{
    if(a == NULL) return;
    output(a->son[0]);
    ans.push_back(a->data);
    output(a->son[1]);
}
int main()
{
    int n, m, l, r;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; ++i)
        root = merge(root, new Treap(i));
    while(m--)
    {
        scanf("%d%d",&l,&r);
        D x = split(root, l+r-1);
        D y = split(x.first, l-1);
        merge(y.second, merge(y.first, x.second));
    }
    output(root);
    for(int i=0; i<ans.size(); ++i) printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
    return 0;
}

 

代码下载地址: https://pan.quark.cn/s/bc087ffa872a "测控电路课后习题详解"文件.pdf是一份极具价值的学术资料,其中系统地阐述了测控电路的基础理论、系统构造、核心特性及其实际应用领域。 以下是对该文献的深入解读和系统梳理:1.1测控电路在测控系统中的核心功能测控电路在测控系统的整体架构中扮演着不可或缺的角色。 它承担着对传感器输出信号进行放大、滤除杂音、提取有效信息等关键任务,并且依据测量与控制的需求,执行必要的计算、处理与变换操作,最终输出能够驱动执行机构运作的指令信号。 测控电路作为测控系统中最具可塑性的部分,具备易于放大信号、转换模式、传输数据以及适应多样化应用场景的优势。 1.2决定测控电路精确度的关键要素影响测控电路精确度的核心要素包括:(1)噪声与干扰的存在;(2)失调现象与漂移效应,尤其是温度引起的漂移;(3)线性表现与保真度水平;(4)输入输出阻抗的特性影响。 在这些要素中,噪声干扰与失调漂移(含温度效应)是最为关键的因素,需要给予高度关注。 1.3测控电路的适应性表现测控电路在测控系统中展现出高度的适应性,具体表现在:* 具备选择特定信号、灵活实施各类转换以及进行信号处理与运算的能力* 实现模数转换与数模转换功能* 在直流与交流、电压与电流信号之间进行灵活转换* 在幅值、相位、频率与脉宽信号等不同参数间进行转换* 实现量程调整功能* 对信号实施多样化的处理与运算,如计算平均值、差值、峰值、绝对值,进行求导数、积分运算等,以及实现非线性环节的线性化处理、逻辑判断等操作1.4测量电路输入信号类型对电路结构设计的影响测量电路的输入信号类型对其电路结构设计产生显著影响。 依据传感器的类型差异,输入信号的形态也呈现多样性。 主要可分为...
### FHQ Treap 数据结构概述 FHQ Treap 是一种无需旋转操作即可保持平衡的二叉查找树(BST),其特性在于既遵循 BST 的性质,即对于任意节点 \(N\),左子树上的所有键值均小于该节点的键值而右子树上的所有键值则都更大;同时也维持着堆的属性——每个节点拥有一个额外分配给它的优先级(通常通过随机数生成),使得父节点总是有着不低于子女们的优先级别[^1]。 这种双重约束确保了即使是在最坏情况下插入序列也能接近理想的对数时间复杂度性能表现。具体而言,当构建一棵由 \(n\) 个互异关键字组成的 FHQ Treap 并且这些关键字对应的优先级被独立均匀分布赋予时,则此树的高度预期大约为 \(\log{n}\)[^3]。 ### FHQ Treap 基本操作解析 #### 插入 Insertion 为了向 FHQ Treap 中添加新元素,在找到合适位置之后并非简单地创建新的叶子节点而是利用分裂(split)与合并(merge)机制完成: - **Split**: 将现有树依据目标数值切割成两部分; - **Merge**: 新建含待插值及其随机化后的高优先生存概率的新根节点连接两侧分割所得之子树形成更新版整体结构。 ```cpp void insert(int& root, int value){ if (!root){ root = new_node(value); return; } int L, R; split(root, value, L, R); root = merge(L, merge(new_node(value), R)); } ``` 这里 `new_node` 函数负责初始化带有指定 key 和随即产生的 priority 的全新节点实例[^4]。 #### 删除 Deletion 移除特定项的过程同样依赖上述提到的基础组件: - 首先定位到需删除的目标节点; - 接下来执行 Split 来分离出含有目标节点的小范围区间; - 最终借助 Merge 方法重组剩余片段而不保留已被剔除的部分。 ```cpp void erase(int& root, int value){ if (!root) return; int L, M, R; split(root, value - 1, L, R); // 左边全部小于value split(R, value, M, R); // 右边全部大于value root = merge(L, R); // 不再包含M中的target node } ``` 以上代码展示了如何高效安全地处理动态集合内的成员变更请求,同时维护良好的渐近运行效率[^5]。 ### 关联功能展示 除了基础 CRUD 外,FHQ Treap 还支持诸如查询第 k 小/大元素、统计某个范围内共有多少条目等高级应用接口的设计实现。这类扩展性得益于灵活运用内部提供的辅助工具函数如 `split()` 和 `merge()`, 它们允许开发者轻松操纵整棵树或其中一部分的状态变化以适应各种实际需求场景下的算法逻辑编写工作。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值