主席树总结

主席树总结

Wc的主席树
Xzy的主席树(建议自己多看!!!)

自己的板子。。。

洛谷题目

随便糊一下

想一想,求i到j中的第k大,是不是就是前j个数把前i个数的影响去掉之后的第k大值(排序实现,但不是暴力...)
……(这不是废话?但这道题时刻记住这一种理解方式有利于理解可持久化线段树的实现)
那么先建一棵主席树,然后只要查询两个时期的线段树,然后找到正好加入的时间点就ojbk了
说的很简单,至于实现,那就自己模拟研究......

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;
}

题单(来自XZY)

  • [ ] [COGS2316]可持久化线段树
  • [X] [Luogu3834]可持久化线段树
  • [X] [Luogu3919]可持久化数组
  • [ ] [SPOJ10628]Count On a Tree
  • [ ] [BZOJ3514]Codechef MARCH14 GERALD07加强版
  • [ ] [BZOJ3123]森林
  • [ ] [BZOJ4571][SCOI2016]美味
  • [ ] [BZOJ4012][HNOI2015]开店
  • [ ] [BZOJ2006][NOI2010]超级钢琴
  • [ ] [BZOJ1926][SDOI2010]粟粟的书架
  • [ ] [BZOJ3932][CQOI2015]任务查询系统
  • [ ] [BZOJ1146]网络管理
  • [ ] 国家集训队middle
  • [ ] [CF757G] Can Bash Save the Day?
  • [ ] SPOJ/Vjudge To the moon(复习模板)
  • [ ] HDU P4251 The Famous ICPC Team Again
  • [ ] SPOJ P3267 D-query
  • [ ] HDU 5919 Sequence II
  • [ ] 洛谷 P3567 [POI2014]KUR-Couriers
  • [ ] CF813E Army Creation
  • [ ] CF484E Sign on Fence
  • [ ] [BZOJ3551][ONTAK2010]Peaks加强版
  • [ ] [BZOJ4556]字符串
  • [ ] [Luogu2617]Dynamic Ranking
  • [ ] [SYZOJ279]滑稽♂树

转载于:https://www.cnblogs.com/cjoierljl/p/9502412.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值