首页 > 代码库 > HDU5107---K-short Problem (线段树区间 合并、第k大)

HDU5107---K-short Problem (线段树区间 合并、第k大)

题意:二维平面上 N 个高度为 Hi 建筑物,M次询问,每次询问输出 位于坐标(x ,y)左下角(也就是xi <= x && yi <= y)的建筑物中的第k高的建筑物的高度,如果不存在输出-1.

思路:可以发现k很小,最大才是10。对于区间第k大的问题,如果k很小的话,线段树也是可以的,,当然这里要用到 区间合并,对于每个节点 记录其 孩子中 前2*k个高度(不一定非要2*k,只要大于k就可以,至于为什么,自己可以想想),进行合并排序。

  1 #include <cstdio>  2 #include <cstdlib>  3 #include <cstring>  4 #include <algorithm>  5 using namespace std;  6   7 const int maxn = 3e4+10;  8 struct Building  9 { 10     int x,y,flag,k,idx; 11     Building (){} 12     Building (int _x,int _y,int _z): x(_x),y(_y),k(_z){} 13     bool operator < (const Building &rhs)const 14     { 15         return x < rhs.x || (x == rhs.x && y < rhs.y) || 16         (x == rhs.x && y == rhs.y && flag < rhs.flag); 17     } 18 }bui[maxn<<1]; 19 struct Seg_tree 20 { 21     int sum,num[25]; 22     Seg_tree (){sum = 0;} 23 }seg[maxn<<3];              //正常来说4倍就够了,可是这题不是maxn而是2*maxn,所以要(2*maxn)*4倍 24 int vec[maxn*2],ans[maxn*2]; 25 void build (int l,int r,int pos) 26 { 27     seg[pos].sum = 0; 28     if (l == r) 29         return; 30     int mid = (l + r) >> 1; 31     build(l,mid,pos<<1); 32     build(mid+1,r,pos<<1|1); 33 } 34 void _sort(int pos) 35 { 36     sort(seg[pos].num,seg[pos].num+seg[pos].sum); 37     seg[pos].sum = min(10,seg[pos].sum); 38 } 39 void push_up(int pos) 40 { 41     int tot = 0; 42     for (int i = 0; i < seg[pos<<1].sum; i++) 43         seg[pos].num[tot++] = seg[pos<<1].num[i]; 44     for (int i = 0; i < seg[pos<<1|1].sum; i++) 45         seg[pos].num[tot++] = seg[pos<<1|1].num[i]; 46     seg[pos].sum = tot; 47     _sort(pos); 48 } 49 void update(int l,int r,int pos,int p,int val) 50 { 51     if (l == r) 52     { 53         seg[pos].num[seg[pos].sum++] = val; 54         _sort(pos);                                            //对当前节点内的高度进行排序 55         return; 56     } 57     int mid = (l + r) >> 1; 58     if (p <= mid) 59         update(l,mid,pos<<1,p,val); 60     else 61         update(mid+1,r,pos<<1|1,p,val); 62     push_up(pos);                                              //左右孩子合并 取出前10个高度 63 } 64 int pre_ans[25],siz; 65 void query(int l,int r,int pos,int ua,int ub) 66 { 67     if (ua <= l && ub >= r) 68     { 69         for (int i = 0; i < seg[pos].sum; i++) 70             pre_ans[siz++] = seg[pos].num[i]; 71         sort(pre_ans,pre_ans+siz); 72         siz = min(10,siz); 73         return; 74     } 75     int mid = (l + r) >> 1; 76     if (ua <= mid) 77         query (l,mid,pos<<1,ua,ub); 78     if (ub > mid) 79         query (mid+1,r,pos<<1|1,ua,ub); 80 } 81 int main(void) 82 { 83     #ifndef ONLINE_JUDGE 84         freopen("in.txt","r",stdin); 85     #endif 86     int n,m; 87     while (~scanf ("%d%d",&n,&m)) 88     { 89         int tot = 0; 90         for (int i = 0; i < n + m ; i++) 91         { 92             int u,v,c; 93             scanf ("%d%d%d",&u,&v,&c); 94             bui[i] = Building (u,v,c); 95             if (i < n) 96                 bui[i].flag = 0; 97             else 98                 bui[i].flag = 1; 99             vec[tot++] = v;100             bui[i].idx = i;101         }102         sort(vec,vec+tot);103         sort(bui,bui+n+m);104         tot = unique(vec, vec + tot) - vec;105         build(1,tot,1);106         for (int i = 0; i < n + m; i++)107         {108             int p = 1 + lower_bound(vec,vec+tot,bui[i].y) - vec;109             if (bui[i].flag == 0)110                 update(1,tot,1,p,bui[i].k);111             else112             {113                 siz = 0;114                 query(1,tot,1,1,p);115                 if (bui[i].k > siz)116                     ans[bui[i].idx] = -1;117                 else118                     ans[bui[i].idx] = pre_ans[bui[i].k-1];119             }120         }121         for (int i = n; i < n + m; i++)122             printf("%d\n",ans[i]);123     }124     return 0;125 }

 

HDU5107---K-short Problem (线段树区间 合并、第k大)