[POJ2104]K-th Number(主席树,静态区间k小)

题目链接:http://poj.org/problem?id=2104

题意:给一个数列,求给定区间第k小的数是多少。

思路:可以按照数字出现的次数为值建立线段树,每插入一个数字就维护一棵线段树,这样求某个区间(比如求[x,y]区间内)的第k小时就可以二分了。当tree[tree[x].l].sum - tree[tree[y].l].sum >= k时去查左儿子,tree[tree[x].l].sum - tree[tree[y].l].sum < k时去查右儿子。数据大,所以要离散化后再做。

  1 /*
  2 ━━━━━┒ギリギリ♂ eye!
  3 ┓┏┓┏┓┃キリキリ♂ mind!
  4 ┛┗┛┗┛┃\○/
  5 ┓┏┓┏┓┃ /
  6 ┛┗┛┗┛┃ノ)
  7 ┓┏┓┏┓┃
  8 ┛┗┛┗┛┃
  9 ┓┏┓┏┓┃
 10 ┛┗┛┗┛┃
 11 ┓┏┓┏┓┃
 12 ┛┗┛┗┛┃
 13 ┓┏┓┏┓┃
 14 ┃┃┃┃┃┃
 15 ┻┻┻┻┻┻
 16 */
 17 #include <algorithm>
 18 #include <iostream>
 19 #include <iomanip>
 20 #include <cstring>
 21 #include <climits>
 22 #include <complex>
 23 #include <fstream>
 24 #include <cassert>
 25 #include <cstdio>
 26 #include <bitset>
 27 #include <vector>
 28 #include <deque>
 29 #include <queue>
 30 #include <stack>
 31 #include <ctime>
 32 #include <set>
 33 #include <map>
 34 #include <cmath>
 35 using namespace std;
 36 #define fr first
 37 #define sc second
 38 #define cl clear
 39 #define BUG puts("here!!!")
 40 #define W(a) while(a--)
 41 #define pb(a) push_back(a)
 42 #define Rint(a) scanf("%d", &a)
 43 #define Rll(a) scanf("%I64d", &a)
 44 #define Rs(a) scanf("%s", a)
 45 #define Cin(a) cin >> a
 46 #define FRead() freopen("in", "r", stdin)
 47 #define FWrite() freopen("out", "w", stdout)
 48 #define Rep(i, len) for(int i = 0; i < (len); i++)
 49 #define For(i, a, len) for(int i = (a); i < (len); i++)
 50 #define Cls(a) memset((a), 0, sizeof(a))
 51 #define Clr(a, x) memset((a), (x), sizeof(a))
 52 #define Full(a) memset((a), 0x7f7f7f, sizeof(a))
 53 #define lrt rt << 1
 54 #define rrt rt << 1 | 1
 55 #define pi 3.14159265359
 56 #define RT return
 57 #define lowbit(x) x & (-x)
 58 #define onecnt(x) __builtin_popcount(x)
 59 typedef long long LL;
 60 typedef long double LD;
 61 typedef unsigned long long ULL;
 62 typedef pair<int, int> pii;
 63 typedef pair<string, int> psi;
 64 typedef pair<LL, LL> pll;
 65 typedef map<string, int> msi;
 66 typedef vector<int> vi;
 67 typedef vector<LL> vl;
 68 typedef vector<vl> vvl;
 69 typedef vector<bool> vb;
 70
 71 const int maxn = 1000010;
 72 int n, m;
 73 int cnt, root[maxn], a[maxn], x, y, k;
 74 typedef struct Node {
 75     int l, r, sum;
 76 }Node;
 77 int h[maxn], hcnt;
 78 Node tree[maxn*40];
 79
 80 int getid(int x) {
 81     return lower_bound(h+1, h+hcnt+1, x) - h;
 82 }
 83
 84 int build(int l, int r) {
 85     int rt = cnt++;
 86     tree[rt].sum = 0;
 87     if(l != r) {
 88         int mid = (l + r) >> 1;
 89         tree[rt].l = build(l, mid);
 90         tree[rt].r = build(mid+1, r);
 91     }
 92     return rt;
 93 }
 94
 95 int update(int rt, int pos, int val) {
 96     int k = cnt++, tmp = k;
 97     tree[k].sum = tree[rt].sum + val;
 98     int l = 1, r = hcnt;
 99     while(l < r) {
100         int mid = (l + r) >> 1;
101         if(pos <= mid) {
102             tree[k].l = cnt++; tree[k].r = tree[rt].r;
103             k = tree[k].l; rt = tree[rt].l;
104             r = mid;
105         }
106         else {
107             tree[k].r = cnt++; tree[k].l = tree[rt].l;
108             k = tree[k].r; rt = tree[rt].r;
109             l = mid + 1;
110         }
111         tree[k].sum = tree[rt].sum + val;
112     }
113     return tmp;
114 }
115
116 int query(int x, int y, int k) {
117     int l = 1, r = hcnt;
118     while(l < r) {
119         int mid = (l + r) >> 1;
120         if(tree[tree[x].l].sum - tree[tree[y].l].sum >= k) {
121             r = mid;
122             x = tree[x].l;
123             y = tree[y].l;
124         }
125         else {
126             l = mid + 1;
127             k -= tree[tree[x].l].sum - tree[tree[y].l].sum;
128             x = tree[x].r;
129             y = tree[y].r;
130         }
131     }
132     return l;
133 }
134
135 int main() {
136     // FRead();
137     cnt = 0;
138     Rint(n); Rint(m);
139     For(i, 1, n+1) {
140         Rint(a[i]);
141         h[i] = a[i];
142     }
143     sort(h+1, h+n+1);
144     hcnt = unique(h+1, h+n+1) - h - 1;
145     root[n+1] = build(1, hcnt);
146     for(int i = n; i >= 1; i--) {
147         root[i] = update(root[i+1], getid(a[i]), 1);
148     }
149     W(m) {
150         Rint(x), Rint(y), Rint(k);
151         printf("%d\n", h[query(root[x], root[y+1], k)]);
152     }
153     return 0;
154 }
时间: 2024-10-15 09:59:12

[POJ2104]K-th Number(主席树,静态区间k小)的相关文章

POJ 2104:K-th Number(主席树静态区间k大)

题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var t:array[0..100000*50]of point; a,b,id,root:array[0..100000]of longint; n,i,m,x,y,k,v,len:longint; procedure qsort(l,h:longint); var i,j,t,m:longint; b

POJ2104-- K-th Number(主席树静态区间第k大)

[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段树,每个节点记录这个区间所包含的元素个数,建树和查询时的区间范围用递归参数传递,然后用二叉查找树的询问方式即可:即如果左边元素个数sum>=K,递归查找左子树第K大,否则递归查找右子树第K – sum大,直到返回叶子的值. 现在我们要回答对于区间[l, r]的第K大询问.如果我们能够得到一个插入原序

HDU3727--Jewel (主席树 静态区间第k大)

Jewel Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 985    Accepted Submission(s): 247 Problem Description Jimmy wants to make a special necklace for his girlfriend. He bought many beads with

[poj 2104]主席树+静态区间第k大

题目链接:http://poj.org/problem?id=2104 主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即可得到第k大(小)元素. #include<cstdio> #include<vector> #include<algorithm> using namespace std; #define lson(i) node[i].lson #define rson(i) node

【POJ2104】K-th Number——主席树

早上刷NOIP的题刷到有点烦就想学点新东西,然后.....一个早上就这样过去了QAQ.虽然主席树不是NOIP考点,但是...或许我能活到省选呢?(美好的幻想) 题目链接 题目的大意就是给定一个长度为n的区间,给出m个询问,每次询问一个区间[l,r]中第k小的树. 主席树(一种可持久化线段树)的入门题. 推荐一发学习资料:戳这里 感觉人家讲得很仔细了我也没什么讲的必要了...... 总算是学了一种可持久化树了,好像也没想象中那么难?这道题的重点在query函数方面,建议自己在纸上模拟一下建树和查询

【POJ2104】K-th Number 主席树?函数式线段树?可持久化线段树?……反正是其中一个

题意:区间静态第K大. 题解: 可持久化线段树. 可持久化线段树: 基本思想:我们维护插入每个节点后的线段树. 朴素写法(MLE+TLE)我们对于每次插入,都复制一棵线段树而后插入,这样保证了"可持久化". 但是显然,时间复杂度和空间复杂度都是n^2的.233. 所以有了优化写法:我们发现每次的插入只有logn个节点被改变,所以只需要这些点新建,其它点都指向原来版本的节点就好了. 空间复杂度nlogn. 然后这道题是区间第K大,对于区间[a,b],插入到b时的线段树,节点的size-(

[知识点]主席树入门 区间k值

入坑主席树主要是因为昨天考试的后两道题不可改2333 而且觉得这个还挺有用,于是果断入坑 不过蒟蒻的我只是在上午看了看大概思路,下午开的运动会没时间码,于是晚上码了出来.但是目前只会无修改的区间K值问题,加上又比较抽象,思路屡了半天才刚刚醒悟,于是写下来记录一下. 不扯那么多辣鸡套路,直接说思路打法(以k小值为例): 我们先要以权值建一颗线段树,然后每个节点记录的是这个节点管辖的范围内数列中数的个数. 我们需要建好多好多线段树.简单来讲呢,就是[1,1],[1,2]···[1,n]这么多颗,每棵

洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)

题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#define gc() getchar() #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=2e5+5,MAXIN=2e6; int n,m,A[N],ref[N],cn

HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)

HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2那个. 思路: 主席树操作,这里的思路是从n到1开始建树.其他就是主席树查询区间第K小,计算区间不同值个数. #include <algorithm> #include <iterator> #include <iostream> #include <cstring&

zoj 2112 Dynamic Rankings(主席树&amp;动态第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They