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             else
112             {
113                 siz = 0;
114                 query(1,tot,1,1,p);
115                 if (bui[i].k > siz)
116                     ans[bui[i].idx] = -1;
117                 else
118                     ans[bui[i].idx] = pre_ans[bui[i].k-1];
119             }
120         }
121         for (int i = n; i < n + m; i++)
122             printf("%d
",ans[i]);
123     }
124     return 0;
125 }
原文地址:https://www.cnblogs.com/oneshot/p/4115487.html