POJ 2104 寻找区间第K数
划分树,时间复杂度O(MlogN),归并树,时间复杂度O(Mlog^3N)。
归并树
#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define BUG puts("here!!!") using namespace std; const int MAX = 100010; class Merger_tree{ public : class Tnode{ public : int l,r; int len() { return r - l;} int mid() { return MID(l,r);} bool in(int ll,int rr) { return l >= ll && r <= rr; } void lr(int ll,int rr){ l = ll; r = rr;} }; Tnode node[MAX<<2]; int seg[20][MAX],a[MAX],n; void init() { memset(seg,0,sizeof(seg)); memset(node,0,sizeof(node)); } void build(int s,int t){ n = t; Merger_build(1,s,t,1); } int find(int x,int y,int k) { return find_rank(n,x,y,k); }; void Merger_build(int t,int l,int r,int deep) { node[t].lr(l, r); if( node[t].len() == 0 ) { seg[deep][l] = a[l]; return ; } int mid = MID(l, r); Merger_build(L(t), l, mid, deep+1); Merger_build(R(t), mid+1, r, deep+1); int k = l,i = l,j = mid+1; while( i <= mid && j <= r ) if( seg[deep+1][i] < seg[deep+1][j] ) seg[deep][k++] = seg[deep+1][i++]; else seg[deep][k++] = seg[deep+1][j++]; while( i <= mid ) seg[deep][k++] = seg[deep+1][i++]; while( j <= r ) seg[deep][k++] = seg[deep+1][j++]; } int find_k(int t,int l,int r,int deep,int val) { if( node[t].in(l,r) ) { int ll = node[t].l, rr = node[t].r; while( ll < rr ) { int mid = MID(ll, rr); if( seg[deep][mid] < val ) ll = mid + 1; else rr = mid; } if( seg[deep][ll] <= val ) return ll - node[t].l + 1; else return ll - node[t].l; } if( node[t].len() == 0 ) return 0; int ans = 0; int mid = node[t].mid(); if( l <= mid ) ans += find_k(L(t), l, r, deep+1, val); if( r >= mid ) ans += find_k(R(t), l, r, deep+1, val); return ans; } int find_rank(int n,int x,int y,int k) { int l = 1,r = n; while( l < r ) { int mid = MID(l, r); if( find_k(1, x, y, 1, seg[1][mid]) < k ) l = mid + 1; else r = mid; } return seg[1][l]; } }; Merger_tree t; int main() { int n,m,x,y,k; while( ~scanf("%d%d",&n,&m) ) { t.init(); for(int i=1; i<=n; i++) scanf("%d",&t.a[i]); t.build(1,n); while( m-- ) { scanf("%d%d%d",&x,&y,&k); int ans = t.find(x,y,k); printf("%d\n",ans); } } return 0; }
划分树
#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define BUG puts("here!!!") using namespace std; const int MAX = 100010; class Parti_tree{ public : class Tnode{ public : int l,r; int len() { return r - l;} int mid() { return MID(l,r);} bool in(int ll,int rr) { return l >= ll && r <= rr; } void lr(int ll,int rr){ l = ll; r = rr;} }; Tnode node[MAX<<2]; int Left[20][MAX], seg[20][MAX], sa[MAX]; void init() { memset(Left,0,sizeof(Left)); memset(node,0,sizeof(node)); } void build(int s,int t){ sort(sa+1,sa+t+1); Parti_build(1,s,t,1); } int find(int s,int t,int k){ return find_rank(1,s,t,1,k); } void Parti_build(int t,int l,int r,int d) { node[t].lr(l, r); if( node[t].len() == 0 ) return ; int mid = MID(l, r), lsame = mid - l + 1; for(int i=l; i<=r; i++) if( seg[d][i] < sa[mid] ) lsame--; int lpos = l,rpos = mid+1,same = 0; for(int i=l; i<=r; i++) { if( i == l ) Left[d][i] = 0; else Left[d][i] = Left[d][i-1]; if( seg[d][i] < sa[mid] ) { Left[d][i]++; seg[d+1][lpos++] = seg[d][i]; } if( seg[d][i] > sa[mid] ) seg[d+1][rpos++] = seg[d][i]; if( seg[d][i] == sa[mid] ) if( same < lsame ) { same++; Left[d][i]++; seg[d+1][lpos++] = seg[d][i]; } else seg[d+1][rpos++] = seg[d][i]; } Parti_build(L(t), l, mid, d+1); Parti_build(R(t), mid+1, r, d+1); } int find_rank(int t,int l,int r,int d,int val) { if( node[t].len() == 0 ) return seg[d][l]; int s,ss; if( l == node[t].l ) { s = Left[d][r]; ss = 0; } else { s = Left[d][r] - Left[d][l-1]; ss = Left[d][l-1]; } if( s >= val ) return find_rank(L(t), node[t].l+ss, node[t].l+ss+s-1, d+1, val); else { int mid = node[t].mid(); int bb = l - node[t].l - ss; int b = r - l + 1 - s; return find_rank(R(t), mid+bb+1, mid+bb+b,d+1,val-s); } } }; Parti_tree t; int main() { int n,m,x,y,k; while( ~scanf("%d%d",&n,&m) ) { t.init(); for(int i=1; i<=n; i++) { scanf("%d",&t.sa[i]); t.seg[1][i] = t.sa[i]; } t.build(1,n); while( m-- ) { scanf("%d%d%d",&x,&y,&k); int ans = t.find(x, y, k); printf("%d\n",ans); } } return 0; }