首页 > 代码库 > 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大)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。