题意:给n个数,m次询问,每次询问L到R中第k小的数是哪个
算法1:划分树
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 7 const int mx=1e5+5; 8 int tree[30][mx]; 9 int sortt[mx]; 10 int sum[30][mx]; 11 12 void build(int l,int r,int c) 13 { 14 if (l==r) return ; 15 int m=(l+r)>>1; 16 int isame=m-l+1; 17 int pl=l,pr=m+1; 18 for (int i=l;i<m;i++) 19 if (tree[c][i]<sortt[m]) isame--; 20 for (int i=l;i<=r;i++){ 21 if (i==l) sum[c][i]=0; 22 else sum[c][i]=sum[c][i-1]; 23 if (tree[c][i]<sortt[m]){ 24 tree[c+1][pl++]=tree[c][i]; 25 sum[c][i]++; 26 } 27 else if ( tree[c][i]==sortt[m]&&isame){ 28 isame--; 29 tree[c+1][pl++]=tree[c][i]; 30 sum[c][i]++; 31 } 32 else tree[c+1][pr++]=tree[c][i]; 33 } 34 build(l,m,c+1); 35 build(m+1,r,c+1); 36 } 37 38 int query(int L,int R,int l,int r,int c,int k){ 39 if (L==R) return tree[c][L]; 40 int s,ss; 41 if (l==L){ 42 s=0; 43 ss=sum[c][r]; 44 } 45 else{ 46 s=sum[c][l-1]; 47 ss=sum[c][r]-s; 48 } 49 int m=(L+R)>>1; 50 if (k<=ss) return query(L,m,L+s,L+s+ss-1,c+1,k); 51 return query(m+1,R,m+1+l-L-s,m+1+r-L-s-ss,c+1,k-ss); 52 } 53 54 int main(){ 55 int n,m; 56 scanf("%d%d",&n,&m); 57 for (int i=1;i<=n;i++){ 58 scanf("%d",&sortt[i]); 59 tree[0][i]=sortt[i]; 60 } 61 sort(sortt+1,sortt+1+n); 62 build(1,n,0); 63 while (m--) 64 { 65 int l,r,k; 66 scanf("%d%d%d",&l,&r,&k); 67 printf("%d\n",query(1,n,l,r,0,k)); 68 } 69 70 }
算法2:主席树
1 /************************************************************* 2 算法:主席树 3 思想:建n+1棵线段树,每颗线段数结构都是一样,先建一棵空树,然 4 后每棵树都在前一棵树的基础上进行修改。 5 把样例按照代码模拟一遍,就很容易理解了。 6 **************************************************************/ 7 #include<cstdio> 8 #include<cstring> 9 #include<algorithm> 10 #include<iostream> 11 #include<vector> 12 using namespace std; 13 14 const int mx=1e5+5; 15 struct Tree ///树的节点 16 { 17 int l,r; ///树的区间 18 int ls,rs; ///树的左右孩子 19 int sum; 20 }; 21 Tree tree[mx*20]; 22 int a[mx],b[mx]; 23 int s[mx],cnt; 24 25 void build(int l,int r,int &node) ///建空树,和线段树差不多 26 { 27 node=++cnt; 28 tree[node].l=l; 29 tree[node].r=r; 30 tree[node].sum=0; 31 if (l==r) return ; 32 int m=(l+r)/2; 33 build(l,m,tree[node].ls); 34 build(m+1,r,tree[node].rs); 35 } 36 37 void inser(int n1,int &n2,int pos) ///在上一棵树的基础上建立新树 38 { 39 n2=++cnt; 40 tree[n2].l=tree[n1].l; ///区间和上一棵树一样 41 tree[n2].r=tree[n1].r; 42 tree[n2].rs=tree[n1].rs; ///保证没有修改的部分和上一棵树一样 43 tree[n2].ls=tree[n1].ls; 44 tree[n2].sum=tree[n1].sum+1; 45 if (tree[n1].l==tree[n1].r) return ; 46 int m=(tree[n1].l+tree[n1].r)/2; 47 if (pos<=m) inser(tree[n1].ls,tree[n2].ls,pos); 48 else inser(tree[n1].rs,tree[n2].rs,pos); 49 } 50 51 int query(int n1,int n2,int k) ///查询的k小的树 52 { 53 if (tree[n1].l==tree[n1].r) 54 { 55 return b[tree[n1].l]; 56 } 57 int cut=tree[tree[n2].ls].sum-tree[tree[n1].ls].sum; 58 if (cut>=k) return query(tree[n1].ls,tree[n2].ls,k); 59 return query(tree[n1].rs,tree[n2].rs,k-cut); 60 } 61 62 int main() 63 { 64 int n,m; 65 scanf("%d%d",&n,&m); 66 for (int i=1;i<=n;i++) 67 { 68 scanf("%d",&a[i]); 69 b[i]=a[i]; 70 } 71 sort(b+1,n+b+1); 72 cnt=0; 73 build(1,n,s[0]); 74 for (int i=1;i<=n;i++) 75 { 76 int pos=lower_bound(b+1,b+n+1,a[i])-b; ///找的a[i]要放的位置 77 inser(s[i-1],s[i],pos); 78 } 79 while (m--) 80 { 81 int l,r,k; 82 scanf("%d%d%d",&l,&r,&k); 83 printf("%d\n",query(s[l-1],s[r],k)); 84 } 85 }