【静态主席树】POJ2104-K-th Number

求区间第k大。裸线段树。

莫队版本:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #define lson l,m
 7 #define rson m+1,r
 8 using namespace std;
 9 const int MAXN=100000+50;
10 int sum[MAXN<<5],L[MAXN<<5],R[MAXN<<5];
11 int a[MAXN],hash[MAXN],T[MAXN],tot=0;
12 int m,n,d;
13
14 int build(int l,int r)
15 {
16     int rt=++tot;
17     sum[rt]=0;
18     if (l<r)
19     {
20         int m=(l+r)>>1;
21         L[rt]=build(lson);
22         R[rt]=build(rson);
23     }
24     return rt;
25 }
26
27 int update(int pre,int l,int r,int x)
28 {
29     int rt=++tot;
30     L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1;
31     if (l!=r)
32     {
33         int m=(l+r)>>1;
34         if (x<=m) L[rt]=update(L[rt],lson,x);
35             else R[rt]=update(R[rt],rson,x);
36     }
37     return rt;
38 }
39
40 int query(int lrt,int rrt,int l,int r,int k)
41 {
42     if (l==r) return l;
43     int num=sum[L[rrt]]-sum[L[lrt]];
44
45     int m=(l+r)>>1;
46     if(num>=k)
47         return query(L[lrt], L[rrt], lson, k);
48     else
49         return query(R[lrt], R[rrt], rson, k-num);
50 }
51
52 void init()
53 {
54     scanf("%d%d",&n,&m);
55     for (int i=1;i<=n;i++)
56     {
57         scanf("%d",&a[i]);
58         hash[i]=a[i];
59     }
60     sort(hash+1,hash+n+1);
61     d=unique(hash+1,hash+n+1)-hash-1;
62     T[0]=build(1,n);
63     for (int i=1;i<=n;i++)
64     {
65         int x=lower_bound(hash,hash+d,a[i])-hash;
66         T[i]=update(T[i-1],1,d,x);
67     }
68 }
69
70 void solve()
71 {
72     for (int i=0;i<m;i++)
73     {
74         int l,r,k;
75         scanf("%d%d%d",&l,&r,&k);
76         int x=query(T[l-1],T[r],1,d,k);
77         printf("%d\n",hash[x]);
78     }
79 }
80
81 int main()
82 {
83     init();
84     solve();
85     return 0;
86 }
时间: 2024-11-10 10:27:13

【静态主席树】POJ2104-K-th Number的相关文章

poj2104 主席树 区间K大 在线 无修改

关于主席树: 主席树(Chairman Tree)是一种离线数据结构,使用函数式线段树维护每一时刻离散之后的数字出现的次数,由于各历史版本的线段树结构一致,可以相减得出区间信息,即该区间内出现的数字和对应的数量,由于在线段树内,左子树代表的数字都小与右子树,便可像平衡树一样进行K大询问.新建一颗树是\(O(logn)\),查询一次也为\(O(logn)\). 比划分树好想&写多了,但是在POJ上比划分树慢一些. CODE: 1 #include <cstdio> 2 #include

ZOJ 2112 Dynamic Rankings(主席树套树状数组+静态主席树)

题意:给定一个区间,求这个区间第k大的数,支持单点修改. 思路:主席树真是个神奇的东西.........速度很快但是也有一个问题就是占用内存的很大,一般来说支持单点修改的主席树套树状数组空间复杂度为O(n*logn*logn), 如果查询较少的话,可以初始的时候用一颗静态主席树,这样空间复杂度可以降为O(n*logn+q*logn*logn),勉强可以过zoj这道题. 这道题看了好久好久才懂...网上题解一般就几句话.......下面是自己的一些理解. 首先静态主席树这个东西其实比较好懂,就是对

静态主席树总结(静态区间的k大)

静态主席树总结(静态区间的k大) 首先我们先来看一道题 给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个正整数,表示这个序列各项的数字. 接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间[l, r][l,r] 内的第k小值. 输出格式: 输出包含k行,每行1个正整数,依次表示每一次查询的结果 对于100%的数据满足:\(1 \leq N, M \leq 2\cdot

poj2104求区间第k小,静态主席树入门模板

看了很久的主席树,最后看https://blog.csdn.net/williamsun0122/article/details/77871278这篇终于看懂了 #include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]为原

poj 2104 静态主席树

我的第一道主席树(静态). 先记下自己对主席树的理解: 主席树的作用是用于查询区间第k大的元素(初始化nlog(n),查询log(n)) 主席树=可持续线段树+前缀和思想 主席树实际上是n棵线段树(由于是可持续化线段树,所以实际上是n个长度为log(n)的链),第i棵线段树保存的是a[1]~a[i]这i个数的值域线段树,每个节点维护的是该值域中元素个数,这个是可以相减的,所以建完树后,查询[lf,rg]的第k大时,保存当前查询的值域区间在lf-1和rg这两棵线段树中的节点u,v(不理解看代码),

静态主席树

[转]主席树:对于序列的每一个前缀建一棵以序列里的值为下标的线段树(所以要先离散化),记录该前缀序列里出现的值的次数:记离散后的标记为1~n; (下面值直接用1~n代替;) 对于区间[x,y]的第k大的值,那么从root[x-1],root[y]开始,t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示区间[x,y]内值在[1,mid]的个数 先判断t是否大于K. 如果t大于k,那么说明在区间[x,y]内存在[1,mid]的数的个数大于k,也就是第k大的值在[1,mi

【Luogu】P3384主席树模板(主席树查询K小数)

YEAH!我也是一个AC主席树模板的人了! 其实是个半吊子 我将尽量详细的讲出我的想法. 主席树太难,我们先搞普通线段树好了 普通线段树怎么做?我的想法是查询K次最小值,每次查完把查的数改成INF,查完再改回来... MDZZ 于是就有了主席树. 先不考虑主席树,我们来考虑一个奇特的线段树. 一般的线段树,数列位置是下标,而把数列维护值作为线段树中存的元素. 那我们如果反过来,把数列元素当做线段树的下标...??? 比如说数列[4 2 3 1] 如果线段树的下标是1.2.3.4......? 那

主席树POJ2104

求区间第k大数是多少 用我惯用的线段树写法似乎不适合写主席树,看别人的代码好半天才看懂 用root表示每一个前缀树的根,思想大致是由第i-1个树构成的树建第i个树,由于加入一个数只需要log级别修改,所以建树效率很高. 主席树的精髓在于可持续化,就是说之前区间的信息不去修改它,递推加入新元素的时候,要新开log个空间来存储.因为主席树本身比较占用空间,只需改变这些空间的指向就可以重复利用不变的空间,达到节省空间的目的. 简而言之,主席树是一种重复利用数据不变的空间,建成空间上只有一颗完整的树,但

POJ 2104 K-th Number 静态主席树(裸

题目链接:点击打开链接 题意: 给定n长的序列,q个询问 下面n个数字给出序列 每个询问[l, r] k ,输出该区间中第k大的数 先建一个n个节点的空树,然后每次从后往前新建一棵树,依附原来的空树建.询问就是在树上二分. #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <vector> #include <iostream> #include <cs