1. 程式人生 > >poj 2104 K-th Number (主席樹入門模板題)

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