poj 2104 K-th Number (主席樹入門模板題)
摘抄了一段主席樹的解釋:所謂主席樹呢,就是對原來的數列[1..n]的每一個字首[1..i](1≤i≤n)建立一棵線段樹,線段樹的每一個節點存某個字首[1..i]中屬於區間[L..R]的數一共有多少個(比如根節點是[1..n],一共i個數,sum[root] = i;根節點的左兒子是[1..(L+R)/2],若不大於(L+R)/2的數有x個,那麼sum[root.left] = x)。若要查詢[i..j]中第k大數時,設某結點x,那麼x.sum[j] - x.sum[i - 1]就是[i..j]中在結點x內的數字總數。而對每一個字首都建一棵樹,會MLE,觀察到每個[1..i]和[1..i-1]只有一條路是不一樣的,那麼其他的結點只要用回前一棵樹的結點即可,時空複雜度為O(nlogn)。
自己的程式碼醜陋,見諒
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
struct node {
int l, r, cnt;
/*
注意!!!
l,r不是指區間,而是節點的序號
cnt是有多少個數字出現
*/
} T[maxn * 20];
int len, n, m, a[maxn], t[maxn], root[maxn], tot;
// root 儲存的是所有歷史記錄
int build(int l, int r) {
int rt = ++tot;
T[rt].l = 0;
T[rt].r = 0;
T[rt].cnt = 0;//建立一棵空樹
if(l == r) return rt;
int mid = (l + r) >> 1;
T[rt].l = build(l, mid);//左右遞迴建立
T[rt].r = build(mid + 1, r);
return rt;
}
int updata(int l, int r, int pre, int x) {
int rt = ++tot;
T[rt] = T[pre];//相當於連線新節點和以前節點的左右子樹
T[rt].cnt++;
if(l == r) return rt;
int mid = (l + r) >> 1;//每次二分新增一個新節點
if(mid >= x)T[rt].l = updata(l, mid, T[pre].l, x);
else T[rt].r = updata(mid + 1, r, T[pre].r, x);
return rt;
}
int query(int l, int r, int pre, int rt, int k) {
if(l == r) return l;
int mid = (l + r) >> 1;
int sum = T[T[rt].l].cnt - T[T[pre].l].cnt;//每次比較兩個節點的左子樹
if(sum >= k) return query(l, mid, T[pre].l, T[rt].l, k);
else return query(mid + 1, r, T[pre].r, T[rt].r, k - sum);//如果在右子樹上別忘了減去sum
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
t[i] = a[i];
}
sort(t + 1, t + 1 + n);//必須離散化
len = unique(t + 1, t + 1 + n) - t - 1;
for(int i = 1; i <= n; i++) {
a[i] = lower_bound(t + 1, t + 1 + len, a[i]) - t;
}
root[0] = build(1, n);
for(int i = 1; i <= n; i++) {
root[i] = updata(1, n, root[i - 1], a[i]);
}
for(int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
printf("%d\n", t[query(1, n, root[u - 1], root[v], w)]);
}
return 0;
}
相關推薦
poj 2104 K-th Number (主席樹入門模板題)
摘抄了一段主席樹的解釋:所謂主席樹呢,就是對原來的數列[1..n]的每一個字首[1..i](1≤i≤n)建立一棵線段樹,線段樹的每一個節點存某個字首[1..i]中屬於區間[L..R]的數一共有多少個(比如根節點是[1..n],一共i個數,sum[root]
POJ 2104 K-th Number(主席樹)
ber sca first n) 次數 example == scan sorted K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 5742
POJ 2104 K-th Number(主席樹,區間第K大的數)
Description You are working for Macrohard company in data structures department. After failing your previous task about key insertion you
poj 2104 K-th Number (主席樹模板)
傳送門 // by spli #include<cstring> #include<cstdio> #include<algorithm> #include<iostream> using namespace
POJ 2104 K-th Number (劃分樹 / 主席樹)
Description You are working for Macrohard company in data structures department. After failing yo
POJ 2104 K-th Number (劃分樹,主席樹寫過了,這次是整體二分解法 )
還是先描述一下題意: 給出一個長度為n的數列,m次詢問區間內的第k大數 對劃分樹,主席樹和整體二分通過這題做了一下比較 劃分樹 1000ms+ 主席樹 2000ms+ 整體二分 1500ms+ 整體二分介於兩者之前,對於這題複雜度約莫是O( (n+m)log(n+m)l
poj2104 K-th Number (主席樹入門題|模板題)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 48751 Accepted: 16447 Case Time Limit: 2000MS Description Y
POJ2104————K-th Number(線段樹,二分法)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 51227 Accepted: 17511 Case Time Limit: 2000MS Description
主席樹(可持久化線段樹)講解 [POJ 2104] K-th Number
題目大意:本題包含多組資料。每組資料都會給你一個數組,包含 n 個數;一共有 m 個詢問,每次詢問輸入三個整數 L , R , k,表示求區間 [ L , R ] 以內第 k 小的數。( 1 ≤ n ≤ 100 000 , 1 ≤ m ≤ 5 000 , 陣
POJ 2104 K-th Number(區間第k大數)(平方切割,歸並樹,劃分樹)
ac代碼 deb rank turn tracking line 查看 div 能夠 題目鏈接: http://poj.org/problem?id=2104 解題思路: 由於查詢的個數m非常大。樸素的求法無法在規定時間內求解。因此應該選用合理的方式維護數據來做到高效
POJ 2104 K-th Number (主席樹)
std +++ esp space ctype == string uniq upd 題意:給定一個序列,然後有 q 個詢問,每次詢問 l - r 區間內的第 k 大的值。 析:很明顯的主席樹,而且還是裸的主席樹,先進行離散化,然後用主席樹進行查詢就好。 代碼如下: #p
Poj 2104 K-th Number 主席樹模版題
OS tdi pda sig signed begin ostream air color 題意:離線詢問[l,r]區間第k大 題解:模版題,入門題 #include <iostream> #include <cstdio> #inclu
POJ 2104 K-th Number 主席樹模板題
題意:給定一個長度為n的無序陣列,然後有m組詢問l r k,求區間[l,r]中的第k大數 思路:以前用劃分樹做過,現在學習主席樹,模板題。個人對主席樹的理解:就是把線段樹更新過程中所有的歷史狀態記錄下來,例如更新m次的話,那麼就會有m種狀態,直接建m棵線段樹的話,時間和空
POJ 2104 K-th Number [主席樹入門]【資料結構】
題目連結:http://poj.org/problem?id=2104 ———————————————————————————————————————————————— K-th Number Time Limit: 20000MS Memory
POJ 2104 K-th Number 主席樹(求區間第k大)
主席書資料 題意:給出n個數,m次詢問,[x,y]內第k小的數時多少?n<=1e5,m<=5000 主席樹:對原序列的每個字首i都建立一個線段樹 維護值域[l,r]中的每個數,在字首i的
poj 2104 K-th Number 主席樹+超級詳細解釋
題目大意:給出一段數列,讓你求[L,R]區間內第幾大的數字! 在這裡先介紹一下主席樹! 如果想了解什麼是主席樹,就先要知道線段樹,主席樹就是n棵線段樹,因為線段樹只能維護最大值或者最小值,要想求出第二大的數字怎麼辦呢?兩顆線段樹唄!好,那麼第n大呢,就可
歸併樹(POJ 2104 K-th Number)
在求解區間第k個數的問題,除了劃分樹以外我們還可以使用另一種高效的方法 ------ 歸併樹。 1、演算法描述 所謂歸併樹,就是利用線段樹的建樹過程,將歸併排序的過程儲存。(不會線段樹:here,不會歸併排序:here)。在說明歸併樹之前我們
poj 2104 K-th Number 區間第K大 二分 離散化 + (莫隊 樹狀陣列/平方分解/線段樹)
題目 題解 比較經典的題目,我用了三個方法來寫。 其中第一種第三種我覺得比較好寫,第二種出現了各種問題。 總的來說第一種速度快,但是程式碼長,第三種速度慢一些,但是程式碼比較短,第二種程式碼和第三種差不多,但是慢了很多,寫起
[POJ 2104]K-th Number
n) 劃分樹 tput lease lap form 我們 歸並 nts Description You are working for Macrohard company in data structures department. After failing your
POJ 2104 K-th Number
poj 2104 working lan 只需要 please lin absolut input nlogn Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 5948