划分树--区间第K元素模板

View Code
  1 //Accepted    2665    703MS    16388K    2972 B    G++
  2 #include <stdio.h>
  3 #include <algorithm>
  4 using namespace std;
  5 #define M 100001
  6 #define LL(x)     ((x)<<1)
  7 #define RR(x)     ((x)<<1|1)
  8 struct Seg_Tree{
  9     int left,right;
 10     int mid() {
 11         return (left + right) >> 1;
 12     }
 13 }tt[M*4];
 14 int len;
 15 int sorted[M];
 16 int toLeft[20][M];
 17 int val[20][M];
 18  
 19 void build(int l,int r,int d,int idx) {
 20     tt[idx].left = l;
 21     tt[idx].right = r;
 22     if(tt[idx].left == tt[idx].right)    return ;
 23     int mid = tt[idx].mid();
 24     int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左边的
 25     for(int i = l ; i <= r ; i ++) {
 26         if(val[d][i] < sorted[mid]) {
 27             lsame --;//先假设左边的数(mid - l + 1)个都等于val_mid,然后把实际上小于val_mid的减去
 28         }
 29     }
 30     int lpos = l;
 31     int rpos = mid+1;
 32     int same = 0;
 33     for(int i = l ; i <= r ; i ++) {
 34         if(i == l) {
 35             toLeft[d][i] = 0;//toLeft[i]表示[ tt[idx].left , i ]区域里有多少个数分到左边
 36         } else {
 37             toLeft[d][i] = toLeft[d][i-1];
 38         }
 39         if(val[d][i] < sorted[mid]) {
 40             toLeft[d][i] ++;
 41             val[d+1][lpos++] = val[d][i];
 42         } else if(val[d][i] > sorted[mid]) {
 43             val[d+1][rpos++] = val[d][i];
 44         } else {
 45             if(same < lsame) {//有lsame的数是分到左边的
 46                 same ++;
 47                 toLeft[d][i] ++;
 48                 val[d+1][lpos++] = val[d][i];
 49             } else {
 50                 val[d+1][rpos++] = val[d][i];
 51             }
 52         }
 53     }
 54     build(l,mid,d+1,LL(idx));
 55     build(mid+1,r,d+1,RR(idx));
 56 }
 57  
 58 int query(int l,int r,int k,int d,int idx) {
 59     if(l == r) {
 60         return val[d][l];
 61     }
 62     int s;//s表示[ l , r ]有多少个分到左边
 63     int ss;//ss表示 [tt[idx].left , l-1 ]有多少个分到左边
 64     if(l == tt[idx].left) {
 65         s = toLeft[d][r];
 66         ss = 0;
 67     } else {
 68         s = toLeft[d][r] - toLeft[d][l-1];
 69         ss = toLeft[d][l-1];
 70     }
 71     if(s >= k) {//有多于k个分到左边,显然去左儿子区间找第k个
 72         int newl = tt[idx].left + ss;
 73         int newr = tt[idx].left + ss + s - 1;//计算出新的映射区间
 74         return query(newl,newr,k,d+1,LL(idx));
 75     } else {
 76         int mid = tt[idx].mid();
 77         int bb = l - tt[idx].left - ss;//bb表示 [tt[idx].left , l-1 ]有多少个分到右边
 78         int b = r - l + 1 - s;//b表示 [l , r]有多少个分到右边
 79         int newl = mid + bb + 1;
 80         int newr = mid + bb + b;
 81         return query(newl,newr,k-s,d+1,RR(idx));
 82     }
 83 }
 84  
 85 int main() {
 86     int T;
 87     scanf("%d",&T);
 88     while(T --) {
 89         int n , m;
 90         scanf("%d%d",&n,&m);
 91         for(int i = 1; i <= n; i++){
 92             scanf("%d",&val[0][i]);
 93             sorted[i] = val[0][i];
 94         }
 95         sort(sorted + 1 , sorted + n + 1);
 96         build(1,n,0,1);
 97         while(m --) {
 98             int l,r,k;
 99             scanf("%d%d%d",&l,&r,&k);
100             printf("区间第K小:%d\n",query(l,r,k,0,1));
101             k = r - l + 2 - k;
102             printf("区间第K大:%d\n",query(l,r,k,0,1));
103         }
104     }
105     return 0;
106 }
posted @ 2012-09-18 19:49  Wheat″  阅读(149)  评论(0)    收藏  举报