主席树模板(可持久化线段树)

主席树模板(可持久化线段树)

洛谷题目

code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<ctime>
#include<queue>
#include<stack>
#define rg register
#define il inline
#define lst long long
#define N 200050
using namespace std;

int n,Q,cnt;
int rank[N],root[N];
struct NUMS{
    int v,num;
}jlr[N];
struct TREE{
    int v,ls,rs;
}ljl[N*20];

il int read()
{
    rg int s=0,m=1;rg char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')m=-1,ch=getchar();
    while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    return s*m;
}

il int cmp(rg const NUMS &a,rg const NUMS &b){return a.v<b.v;}

void Update(rg int &now,rg int ll,rg int rr,rg int xx)
//              当前节点,   左边界,   右边界  ,加入的值
//其实这个函数都是板子
{
    ljl[++cnt]=ljl[now];
    now=cnt;
    ljl[now].v++;
    if(ll==rr)return;
    rg int mid=(ll+rr)>>1;
    if(xx<=mid)Update(ljl[now].ls,ll,mid,xx);
    else Update(ljl[now].rs,mid+1,rr,xx);
}

int Query(rg int u,rg int v,rg int ll,rg int rr,rg int kk)
//在ll-1版本上的u点,在rr版本上的v点,左边界,右边界,要找的标号
{
    if(ll==rr)return ll;
    rg int num=ljl[ljl[v].ls].v-ljl[ljl[u].ls].v;//(以左孩子为例)
    //Rank指的是v时间的线段树和u时期的线段树之间加了几个点(我们要找中间第k个加入的点)
    rg int mid=(ll+rr)>>1;//递归中"二分"地找
    if(kk<=num)return Query(ljl[u].ls,ljl[v].ls,ll,mid,kk);
    //如果左孩子里面加了比 要找的序号 数量更多的数,去左孩子上find啊(右孩子的类推)
    else return Query(ljl[u].rs,ljl[v].rs,mid+1,rr,kk-num);//算上左孩子上加入的数量造成的贡献
}

int main()
{
    n=read(),Q=read();
    for(rg int i=1;i<=n;++i)jlr[i].v=read(),jlr[i].num=i;
    sort(jlr+1,jlr+n+1,cmp);
    for(rg int i=1;i<=n;++i)rank[jlr[i].num]=i;//离散化一波

    for(rg int i=1;i<=n;++i)
    {
        root[i]=root[i-1];//按时间顺序建一棵主席树
        Update(root[i],1,n,rank[i]);//把节点都加进去,模拟一下"更新"函数的过程
    }
    for(rg int i=1;i<=n;++i)
    {
        rg int ll=read(),rr=read(),k=read();
        printf("%d\n",jlr[Query(root[ll-1],root[rr],1,n,k)].v);
    }
    return 0;
}
/*
  想一想,求i到j中的第k大,是不是就是前j个数把前i个数的影响去掉之后的第k大值(排序实现,但不是暴力...)
  ……(这不是废话?但这道题时刻记住这一种理解方式有利于理解可持久化线段树的实现)
  那么先建一棵主席树,然后只要查询两个时期的线段树,然后找到正好加入的时间点就ojbk了
  说的很简单,至于实现,那就自己模拟研究......
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值