主席树 poj 2104 K-th Number

本文介绍了主席树(可持久化线段树)的基本概念、构建方法及其实现细节。主席树能够高效地处理序列更新与查询操作,尤其适用于需要记录历史版本的应用场景。

主席树又名可持久化线段树。

我们先撇开可持久化看看主席树是怎么实现的。维护一个长度为n的序列,我们可以建一颗线段树来维护,最上的根节点代表的区间是[1,n]。

我们知道线段树的形态由你给的[l,r],既维护的区间长度决定,现在我要为这个序列的每一个前缀建一棵线段树,每一棵线段树最上的根节点代表的区间依然是[1,n],所以这n棵线段树的结构是一模一样的。

这里的线段树不是普通的线段树而是权值线段树,既它维护的不是序列里的每个ai的值而是整个序列的第几大。对每个ai,插入树中不是ai值而是它是第几大v,接下来从根节点开始v与对应区间的mid比较,小于等于mid就划到左子树,否则划到右子树,直到叶子节点。整个过程像极了二叉搜索树,可以类比理解。

说完建树我们来看看如何实现可持久化。根据clj的论文,可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本、同时充分利用它们之间的共同数据来减少时间和空间消耗。那么哪些地方可以“充分利用它们之间的共同数据”,第i棵线段树建树过程中一个v如果插到左子树,那么当前结点的右子树和第i-1棵线段树对应节点是一模一样的,所以我们只需要把第i棵线段树当前结点的右子树指向第i-1棵线段树对应节点就行了。如果插入右边,同理。这样就实现了可持久化。

下面是几个重要结论:

1、建第i棵线段树,只建了logn个节点,因为每次插入操作只产生一个节点另一个节点是复用的。

2、建树过程中第i棵线段树只与第i-1棵线段树有关。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;
const int maxn=1e5+7;

struct node{
    int ls,rs,sum;
}data[maxn*20];
int cnt;
int root[maxn];
int a[maxn],b[maxn],mp[maxn];
int build(int l,int r){
    int t=cnt++;
    data[t].sum=0;
    if(l==r)return t;
    int mid=l+r>>1;
    data[t].ls=build(l,mid);
    data[t].rs=build(mid+1,r);
    return t;
}
int update(int k,int l,int r,int v){
    int t=cnt++;
    data[t].sum=data[k].sum+1;
    if(l==r)return t;
    int mid=l+r>>1;
    if(v<=mid){
        data[t].rs=data[k].rs;
        data[t].ls=update(data[k].ls,l,mid,v);
    }
    else {
        data[t].ls=data[k].ls;
        data[t].rs=update(data[k].rs,mid+1,r,v);
    }
    return t;
}
int query(int t1,int t2,int l,int r,int v){
    if(l==r)return l;
    int mid=l+r>>1;
    int w=data[data[t2].ls].sum-data[data[t1].ls].sum;
    if(v<=w) return query(data[t1].ls,data[t2].ls,l,mid,v);
    else return query(data[t1].rs,data[t2].rs,mid+1,r,v-w);
}

void debug(int t,int l,int r){
    printf("l==%d r==%d sum==%d\n",l,r,data[t].sum);
    if(l==r)return ;
    int mid=l+r>>1;
    debug(data[t].ls,l,mid);
    debug(data[t].rs,mid+1,r);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        cnt=1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+n+1);
        int len=unique(b+1,b+1+n)-(b+1);
        for(int i=1;i<=n;i++){
            int t=lower_bound(b+1,b+1+len,a[i])-(b+1)+1;
            mp[t]=a[i];a[i]=t;
        }
        root[0]=build(1,len);
        for(int i=1;i<=n;i++){
            root[i]=update(root[i-1],1,len,a[i]);
        }
        /*for(int i=0;i<=n;i++){
            printf("----i==%d------\n",i);
            debug(root[i],1,len);
        }*/
        for(int i=0;i<m;i++){
            int l,r,v;
            scanf("%d%d%d",&l,&r,&v);if(l>r)swap(l,r);
            printf("%d\n",mp[query(root[l-1],root[r],1,len,v)]);
        }
    }
    return 0;
}




代码下载地址: https://pan.quark.cn/s/bc087ffa872a "测控电路课后习题详解"文件.pdf是一份极具价值的学术资料,其中系统地阐述了测控电路的基础理论、系统构造、核心特性及其实际应用领域。 以下是对该文献的深入解读和系统梳理:1.1测控电路在测控系统中的核心功能测控电路在测控系统的整体架构中扮演着不可或缺的角色。 它承担着对传感器输出信号进行放大、滤除杂音、提取有效信息等关键任务,并且依据测量与控制的需求,执行必要的计算、处理与变换操作,最终输出能够驱动执行机构运作的指令信号。 测控电路作为测控系统中最具可塑性的部分,具备易于放大信号、转换模式、传输数据以及适应多样化应用场景的优势。 1.2决定测控电路精确度的关键要素影响测控电路精确度的核心要素包括:(1)噪声与干扰的存在;(2)失调现象与漂移效应,尤其是温度引起的漂移;(3)线性表现与保真度水平;(4)输入输出阻抗的特性影响。 在这些要素中,噪声干扰与失调漂移(含温度效应)是最为关键的因素,需要给予高度关注。 1.3测控电路的适应性表现测控电路在测控系统中展现出高度的适应性,具体表现在:* 具备选择特定信号、灵活实施各类转换以及进行信号处理与运算的能力* 实现模数转换与数模转换功能* 在直流与交流、电压与电流信号之间进行灵活转换* 在幅值、相位、频率与脉宽信号等不同参数间进行转换* 实现量程调整功能* 对信号实施多样化的处理与运算,如计算平均值、差值、峰值、绝对值,进行求导数、积分运算等,以及实现非线性环节的线性化处理、逻辑判断等操作1.4测量电路输入信号类型对电路结构设计的影响测量电路的输入信号类型对其电路结构设计产生显著影响。 依据传感器的类型差异,输入信号的形态也呈现多样性。 主要可分为...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值