1. 程式人生 > >HDU 2665 Kth number(主席樹靜態區間第K大)題解

HDU 2665 Kth number(主席樹靜態區間第K大)題解

可持久化 unique algorithm using 主席樹 可持久化線段樹 long spa 靜態區

題意:問你區間第k大是誰

思路:主席樹就是可持久化線段樹,他是由多個歷史版本的權值線段樹(不是普通線段樹)組成的。

具體可以看q學姐的B站視頻

代碼:

#include<cmath>
#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef 
long long ll; typedef unsigned long long ull; const int maxn = 1e5 + 10; const int M = maxn * 30; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1000000007; int n, q, tot; int a[maxn], root[maxn]; vector<int> st; int getId(int x){ return lower_bound(st.begin(), st.end(),x) - st.begin() + 1
; } struct node{ int lson, rson; int sum; }T[maxn * 40]; void update(int l, int r, int &now, int pre, int v, int pos){ T[++tot] = T[pre], T[tot].sum += v, now = tot; if(l == r) return; int m = (l + r) >> 1; if(m >= pos) update(l, m, T[now].lson, T[pre].lson, v, pos);
else update(m + 1, r, T[now].rson, T[pre].rson, v, pos); } int query(int l, int r, int pre, int now, int k){ if(l == r) return l; int m = (l + r) >> 1; int sum = T[T[now].lson].sum - T[T[pre].lson].sum; if(sum >= k) return query(l, m, T[pre].lson, T[now].lson, k); else return query(m + 1, r, T[pre].rson, T[now].rson, k - sum); } int main(){ int t; scanf("%d", &t); while(t--){ tot = 0; scanf("%d%d", &n, &q); st.clear(); for(int i = 1; i <= n; i++) scanf("%d", &a[i]), st.push_back(a[i]); sort(st.begin(), st.end()); st.erase(unique(st.begin(), st.end()), st.end()); for(int i = 1; i <= n; i++) update(1, n, root[i], root[i - 1], 1, getId(a[i])); while(q--){ int l, r, k; scanf("%d%d%d", &l, &r, &k); printf("%d\n", st[query(1, n, root[l - 1], root[r], k) - 1]); } } return 0; }

HDU 2665 Kth number(主席樹靜態區間第K大)題解