hdu 2665 Kth number
题意:无修改的区间第k小问题。
p.s.终于能用三种方法搞定这道题了,开心~
划分树的方法喜闻乐见;
线段树套平衡树然后二分枚举答案,写起来比较麻烦;
今天刚刚想明白函数式线段树>_<,发现写这个还挺方便;
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = (int)3e6+10; 6 const int maxn = (int)1e5; 7 int lson[N],rson[N],sum[N]; 8 int Time[N]; 9 int total; 10 int s[N],X[N]; 11 void pushup(int root){ 12 sum[root] = sum[lson[root]] + sum[rson[root]]; 13 } 14 int build(int L,int R){ 15 int now = ++total; 16 if(L==R){ 17 lson[now] = rson[now] = 0; 18 sum[now] = 0; 19 return now; 20 } 21 int m=(L+R)>>1; 22 lson[now] = build(L,m); 23 rson[now] = build(m+1,R); 24 pushup(now); 25 return now; 26 } 27 int update(int root,int pos,int L,int R){ 28 int now = ++total; 29 if(L==R){ 30 sum[now] = sum[root] + 1; 31 lson[now] = rson[now] = 0; 32 return now; 33 } 34 int m=(L+R)>>1; 35 if(pos<=m){ 36 lson[now] = update(lson[root],pos,L,m); 37 rson[now] = rson[root]; 38 }else{ 39 lson[now] = lson[root]; 40 rson[now] = update(rson[root],pos,m+1,R); 41 } 42 pushup(now); 43 return now; 44 } 45 int ask(int root1,int root2,int k,int L,int R){ 46 if(L==R){ 47 return X[L]; 48 } 49 int number = sum[lson[root2]] - sum[lson[root1]]; 50 int m=(L+R)>>1; 51 if(number >= k) 52 return ask(lson[root1],lson[root2],k,L,m); 53 else 54 return ask(rson[root1],rson[root2],k-number,m+1,R); 55 } 56 int main(){ 57 int T;scanf("%d",&T); 58 int n,m; 59 while(T--){ 60 scanf("%d%d",&n,&m); 61 int cnt = 0; 62 for(int i=1;i<=n;i++){ 63 scanf("%d",&s[i]); 64 X[++cnt] = s[i]; 65 } 66 sort(X+1,X+1+cnt); 67 int all = 1; 68 for(int i=2;i<=cnt;i++) 69 if(X[i]!=X[i-1])X[++all] = X[i]; 70 total = 0; 71 Time[0] = build(1,all); 72 for(int i=1;i<=n;i++){ 73 int pos = lower_bound(X+1,X+1+all,s[i])-X; 74 Time[i] = update(Time[i-1],pos,1,all); 75 } 76 while(m--){ 77 int L,R,k; 78 scanf("%d%d%d",&L,&R,&k); 79 printf("%d\n",ask(Time[L-1],Time[R],k,1,all)); 80 } 81 } 82 return 0; 83 }