主席樹 靜態區間第k大


 1 /*
 2 主席樹:對於序列的每一個前綴建一棵以序列里的值為下標的線段樹(所以要先離散化),
 3 記錄該前綴序列里出現的值的次數;
 4 記離散后的標記為1~n; (下面值直接用1~n代替;) 
 5 對於區間[x,y]的第k大的值,那么從root[x-1],root[y]開始,
 6 t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示區間[x,y]內值在[1,mid]的個數 
 7 先判斷t是否大於K,如果t大於k,那么說明在區間[x,y]內存在[1,mid]的數的個數大於k,
 8 也就是第k大的值在[1,mid]中,否則在[mid+1,r]中;
 9 
10 這樣我們依次同時從root[x-1],root[y]往下走
11 當l==r時 第k大的值就是離散后標記為l的值;
12 
13 如果每棵線段都建完整的化,n*(n<<2)肯定會mle,
14 我們發現對於前綴[1,i]和前綴[1,i+1]的線段樹,如果b[i+1]<=mid (b[i+1]表示a[i+1]離散后的標記)
15 那么線段樹i和線段樹i+1的左邊是完全相同的,根本不需要在建,只需要用指針指一下就好;
16 那么對於一棵新的線段樹其實我們最多要建的節點數為log(n);nlog(n)的節點數還是可以忍受的;
17  
18 
19  
20 */
21 #include<cstdio>
22 #include<cstring>
23 #include<iostream>
24 #include<algorithm>
25 #include<cmath>
26 #include<cstdlib>
27 #define w(i) T[(i)].w
28 #define ls(i) T[(i)].ls
29 #define rs(i) T[(i)].rs
30 using namespace std;
31 const int N=100000+10;
32 struct node{
33     int ls,rs,w;
34     node(){ls=rs=w=0;}
35 }T[N*20];
36 int a[N],b[N],p[N],root[N],sz;
37 int cmp(int i,int j){
38     return a[i]<a[j];
39 }
40 int n,m;
41 void ins(int &i,int l,int r,int x){
42     T[++sz]=T[i]; i=sz;
43     w(i)++;
44     if (l==r) return;
45     int m=(l+r)>>1;
46     if (x<=m) ins(ls(i),l,m,x);
47     else ins(rs(i),m+1,r,x);
48 }
49 int query(int i,int j,int l,int r,int k){
50     if (l==r) return l;
51     int t=w(ls(j))-w(ls(i));
52     int m=(l+r)>>1;
53     if (t>=k) return query(ls(i),ls(j),l,m,k);
54     else return query(rs(i),rs(j),m+1,r,k-t);
55 }
56 int main(){
57     int Cas;scanf("%d",&Cas);
58     while (Cas--){
59         root[0]=0;
60         scanf("%d%d",&n,&m);
61         for (int i=1;i<=n;i++){
62             scanf("%d",&a[i]);p[i]=i;
63         }
64         sort(p+1,p+1+n,cmp);//間接排序,p[i]表示第i小的值在a[]中的下標; 
65         for (int i=1;i<=n;i++) b[p[i]]=i;//離散化 
66         /*
67         for (int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
68         for (int i=1;i<=n;i++) cout<<p[i]<<" ";cout<<endl;
69         for (int i=1;i<=n;i++) cout<<b[i]<<" ";cout<<endl;
70         */
71         sz=0;
72         for (int i=1;i<=n;i++){
73             root[i]=root[i-1];
74             ins(root[i],1,n,b[i]);
75         }
76         for (int i=0;i<m;i++){
77             int x,y,k;scanf("%d%d%d",&x,&y,&k);
78             int t=query(root[x-1],root[y],1,n,k);
79             printf("%d\n",a[p[t]]);
80         }
81     }
82     return 0;
83 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM