题意:给出1e5个数,向你提5000问,L到R间的第K个数是多少?

————————————————————————————————————————————————————————

这个题着实没有其它很好的办法,是主席树的经典题目。

主席树,又叫可持久化线段树或者函数式线段树。我只知道这些了,据说是一位大神没学会划分树就自己搞了这么个替代品,结果,比原来的还要强。哎~,真不知道这群大神的脑子是咋整的,膜拜吧!

本人水平有限,这是我见过的最神奇的数据结构了,感觉比伸展树、熟练剖分神奇多了,鼓捣了大半天才明白其中的原理。

说一下思路:

因为是求第k大的数,所以线段树是不行的,因为数是排好序的,所以伸展树好像也不好解决。

所以主席树用到了前缀和的思想,如果知道每个数在L前出现了几次,R前出现了几次,做差就可以在L~R间出现了几次,自然也就知道k大了!

所以,第一步把所有的数排序、去重。

数列:2 4 6 8 8 6 4 2

hash:2 4 6 8

数列变为:1 2 3 4 4 3 2 1(就是各个数在hash中的排序)

第二部建n+1个线段树,就是按照数列的顺序每读入一个数就建一个线段树,把新树在上一颗树的基础上把这个数字按照去重后的排序加入当前线段树。

这样求L~R的k值就用线段树R减去线段树L-1,在差中找k大值就可以了。

......

出现的问题:超空间

这个事大神替我们想到了,那就是每一个线段树与上一个线段树只有一条路径(根到叶)不同,所以,新树除了这条路径外所有节点都用上一个线段树的。

这样空间为第一颗线段树(4*n)+每个数字一条链(n*logn)

代码敲了1天多,主要是本人习惯于用指针和new,但是这次点太多,超时了。没办法只好给出数组模拟指针。ok!

网上有人说可以一次性malloc多个,这样可以省时通过,没来得及试,不过应该可以,但是就没有了指针+new的灵活性,不做也罢。

但是没舍得把指针的丢掉,这个理解起来清楚容易,哎~,就这麽着吧!

————————————————————————————————————————————————————————

数组版:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5
 6 using namespace std;
 7 const int maxn=100005;
 8 const int maxnn=10000000;
 9 int root[maxn],ls[maxnn],rs[maxnn],cnt[maxnn],tot;
10 int sz[maxn],hash[maxn];
11 void build(int &cur,int l,int r)
12 {
13     cur=tot++;
14     cnt[cur]=0;
15     if(l!=r)
16     {
17         int mid=(l+r)/2;
18         build(ls[cur],l,mid);
19         build(rs[cur],mid+1,r);
20     }
21 }
22 void update(int pre,int ps,int &cur,int l,int r)
23 {
24     cur=tot++;
25     cnt[cur]=cnt[pre]+1;
26     ls[cur]=ls[pre];rs[cur]=rs[pre];
27     if(l==r)return ;
28     int mid=(l+r)/2;
29     if(ps<=mid)update(ls[pre],ps,ls[cur],l,mid);
30     else update(rs[pre],ps,rs[cur],mid+1,r);
31 }
32 int query(int lt,int rt,int l,int r,int k)
33 {
34     if(l==r)return l;
35     int mid=(l+r)/2,cha=cnt[ls[rt]]-cnt[ls[lt]];
36     if(k<=cha)return query(ls[lt],ls[rt],l,mid,k);
37     else return query(rs[lt],rs[rt],mid+1,r,k-cha);
38 }
39 int main()
40 {
41     int m,n,l,r,k;
42     while(scanf("%d%d",&n,&m)==2)
43     {
44         for(int i=1;i<=n;++i)
45         {
46             scanf("%d",sz+i);
47             hash[i]=sz[i];
48         }
49         sort(hash+1,hash+n+1);
50         int siz=unique(hash+1,hash+1+n)-hash-1;
51         for(int i=1;i<=n;++i)
52             sz[i]=lower_bound(hash+1,hash+1+siz,sz[i])-hash;
53         tot=0;
54         build(root[0],1,siz);
55         for(int i=1;i<=n;++i)
56             update(root[i-1],sz[i],root[i],1,siz);
57         while(m--)
58         {
59             scanf("%d%d%d",&l,&r,&k);
60             printf("%d\n",hash[query(root[l-1],root[r],1,siz,k)]);
61         }
62     }
63     return 0;
64 } 

View Code

指针版(由于多次malloc,超时了)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=100005;
 7 struct node
 8 {
 9     int cnt;
10     node *ch[2];
11     int l,r;
12 }* root[maxn];
13 int n,mm,l,r,k;
14 int sz[maxn],hash[maxn];
15
16 void readint(int &x)
17 {
18     char c=getchar();
19     int f=1;
20     for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-f;
21     x=0;
22     for(;c<='9'&&c>='0';c=getchar())x=x*10+c-'0';
23     x=x*f;
24 }
25 void build(node * &cur,int l,int r)
26 {
27     cur=(node *)malloc(sizeof(node));
28     cur->cnt=0;
29     cur->ch[0]=cur->ch[1]=NULL;
30     cur->l=l;cur->r=r;
31     if(l!=r)
32     {
33         int mid=(l+r)/2;
34         build(cur->ch[0],l,mid);
35         build(cur->ch[1],mid+1,r);
36     }
37 }
38 void update(node * pre,int ps,node * &cur,int l,int r)
39 {
40     cur=(node *)malloc(sizeof(node));
41     cur->cnt=pre->cnt+1;
42     cur->l=pre->l;cur->r=pre->r;
43     cur->ch[0]=pre->ch[0];
44     cur->ch[1]=pre->ch[1];
45     if(l==r)return ;
46     int mid=(l+r)/2;
47     if(ps<=mid)update(pre->ch[0],ps,cur->ch[0],l,mid);
48     else update(pre->ch[1],ps,cur->ch[1],mid+1,r);
49 }
50 int query(node * lt,node *rt,int l,int r,int k)
51 {
52     if(l==r)return l;
53     int mid=(l+r)/2,cha=rt->ch[0]->cnt - lt->ch[0]->cnt;
54     if(k<=cha)return query(lt->ch[0],rt->ch[0],l,mid,k);
55     else return query(lt->ch[1],rt->ch[1],mid+1,r,k-cha);
56 }
57 int main()
58 {
59     while(scanf("%d%d",&n,&mm)==2)
60     {
61         for(int i=1;i<=n;++i)
62         {
63             readint(sz[i]);
64             hash[i]=sz[i];
65         }
66         sort(hash+1,hash+n+1);
67         int siz=unique(hash+1,hash+n+1)-hash-1;
68         for(int i=1;i<=n;++i)
69             sz[i]=lower_bound(hash+1,hash+siz+1,sz[i])-hash;
70         build(root[0],1,siz);
71         for(int i=1;i<=n;++i)
72             update(root[i-1],sz[i],root[i],1,siz);
73         while(mm--)
74         {
75             readint(l);readint(r);readint(k);
76             printf("%d\n",hash[query(root[l-1],root[r],1,siz,k)]);
77         }
78     }
79     return 0;
80 }

View Code

转载于:https://www.cnblogs.com/gryzy/p/6249193.html

POJ2104 K-TH NUMBER 传说中的主席树相关推荐

  1. 【无码专区10】第K大查询(双向链表 /主席树+st表)

    已自我实现,但还是归入无码专区序列.哈哈哈哈哈 对于my idea部分,我的每一个想法都实现了,可供参考. problem 给定一个 1∼n1\sim n1∼n 的排列和 kkk,求所有 r−l+1≥ ...

  2. K-th Closest Distance HDU - 6621(第k小绝对值+主席树+二分)

    You have an array: a1, a2, , an and you must answer for some queries. For each query, you are given ...

  3. zoj 2112 树状数组 套主席树 动态求区间 第k个数

    总算是把动态求区间第k个数的算法看明白了. 在主席树的基础上,如果有修改操作,则要通过套树状数组来实现任意区间求第k小的问题. 刚开始看不明白什么意思,现在有一点理解.树状数组的每个元素是一个线段树, ...

  4. [BZOJ3932][CQOI2015]任务查询系统(差分+主席树)

    题面 分析 对于一个区间修改(s,e,v),我们可以将它差分,这样就变成了单点修改s和e+1(s插入,t+1删除) 我们用主席树维护差分数组的前缀和,第i棵主席树维护区间[1,i]之间的所有差分值 那 ...

  5. 主席树初探--BZOJ1901: Zju2112 Dynamic Rankings

    n<=10000的序列做m<=10000个操作:单点修改,查区间第k小. 所谓的主席树也就是一个值域线段树嘛..不过在这里还是%%fotile 需要做一个区间查询,由于查第k小,需要一些能 ...

  6. 最详细的主席树(不修改,待修改) BZOJ 1901

    By Bartholomew 前置知识: 1.树状数组 2.线段树 主席树 模板是干什么的,其实就是询问区间第k大 不支持修改: 复杂度 O(nlogn) O ( n l o g n ) O(nlog ...

  7. poj2104 k-th number 主席树入门讲解

    poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树   刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...

  8. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

  9. POJ_2104 K-th Number 【主席树】

    一 题面 K-th Number 二 分析 第一个主席树的题,感触蛮多吧,几个关键点就是可持久化数据结构,这里的主席树其实就是保留了之前各个版本的权值线段树,然后利用权值线段树和历史版本可以进行相加减 ...

  10. array(2019CCPC网络预选赛 hdu6703主席树+set)主席树求大于等于k的最小值

    Problem Description You are given an array a1,a2,-,an(∀i∈[1,n],1≤ai≤n). Initially, each element of t ...

最新文章

  1. 智源研究院发布“源创计划”,助力人工智能创业项目加速
  2. ECCV 2020 | 首届GigaVision挑战赛揭榜,双赛道冠军技术干货分享
  3. 两个奇技淫巧,将 Docker 镜像体积减小 99%
  4. JAVA相关基础知识(一)
  5. [译]深度神经网络的多任务学习概览(An Overview of Multi-task Learning in Deep Neural Networks)...
  6. [攻防世界 pwn]——反应釜开关控制
  7. 【数据结构】用栈解决表达式求值问题
  8. qt android 应用程序图标大小,vs+qt 设置应用程序图标
  9. java文件读取的总结_java 读取文件方法的总结
  10. JAVA组件使用---UUID使用方法
  11. 网址大全:国外超级便宜空间
  12. Bailian2699 自整除数【进制】
  13. 医学图像填洞处理-image fill holes
  14. RocksDB调优指南
  15. ICLR 2022 | 合作博弈新范式:为可解释性等机器学习估值问题提供新方法
  16. 64位锐捷多网卡、VMWareNat模式、ICS共享破解
  17. CentOS8 启动错误,enter emergency mode 报错 Failed to mount /sysroot 解决方法
  18. 2013-07-22 码市-武汉 返程票
  19. Mac 编译安装zlib
  20. 读书笔记-精准努力-对待失败的正确思维

热门文章

  1. 系统集成Nacos和Feign
  2. android 重新点击图标显示不出来了,android开发怎么弄成,点击图标后弹出一个消息框。主界面不显示...
  3. Linux系统编程 -- 多线程之基于环形队列的生产者与消费者模型
  4. c++ static 关键字总结
  5. textedit实时显示位置_奉化“实时公交”来了!再也不用在多变的天气里等公交啦!...
  6. jQuery的回调支持
  7. Spring AOP(五)之Around增强处理
  8. SuperPoint学习---demo代码理解
  9. 矩阵分解SVD在推荐系统中的应用
  10. TortoiseSVN 使用详细步骤(三):安装