hdu 2665 Kth number(函式化線段樹)
阿新 • • 發佈:2019-01-26
題意:給定一個序列,問區間內第K大的數是多少。
#include<cstdio> #include<iostream> #include<algorithm> #include<map> using namespace std; #define maxn 100005 #define lson l,mid #define rson mid+1,r map<int,int>ms; int node=0; int head[maxn],a[maxn],b[maxn],sum[maxn<<5],L[maxn<<5],R[maxn<<5]; //函式化線段樹就是在保留之前節點的基礎上新建節點,並且利用之前的節點進行壓縮空間。 //此處是n*logn的空間複雜度。利用了區間數值數目的可加性。 //[1,l] 的線段樹儲存的是權值在到al為止(1,num)範圍內數值的出現次數。 //兩個線段樹相減就是在區間範圍內某些數字的出現次數。進而統計第K大的數字。 void init() { //memset(L,0,sizeof(L)); // memset(R,0,sizeof(R)); memset(head,0,sizeof(head)); node=0;ms.clear(); } void build(int &o,int l,int r)//dfs序建立基礎線段樹 { o=++node;sum[o]=0; if(l>=r)return; int mid=(l+r)>>1; build(L[o],lson); build(R[o],rson); } void update(int pre,int &o,int l,int r,int x)//pre表示同樣位置的上一棵樹節點 { o=++node; L[o]=L[pre];R[o]=R[pre];sum[o]=sum[pre]+1; int mid=(l+r)>>1; if(l>=r)return; if(x<=mid) update(L[pre],L[o],lson,x); else update(R[pre],R[o],rson,x); } int query(int l,int r,int a,int b,int k) { if(l==r)return l; int mid=(l+r)>>1; int x=sum[L[b]]-sum[L[a]]; if(x>=k) return query(lson,L[a],L[b],k); else return query(rson,R[a],R[b],k-x); } int main() { int t,l,r,k; scanf("%d",&t); while(t--){ int n,m; init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); int num=unique(b+1,b+n+1)-b-1; for(int i=1;i<=num;i++)ms[b[i]]=i; build(head[0],1,n); for(int i=1;i<=n;i++){ update(head[i-1],head[i],1,num,ms[a[i]]); } while(m--){ scanf("%d%d%d",&l,&r,&k); printf("%d\n",b[query(1,num,head[l-1],head[r],k)]); } } return 0; }