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\n",ans[i]);
123     }
124     return 0;
125 }
时间: 2024-10-06 21:13:09

HDU5107---K-short Problem (线段树区间 合并、第k大)的相关文章

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

hdu 3308(线段树区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6069    Accepted Submission(s): 2635 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 4339 线段树区间合并

Query Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2573    Accepted Submission(s): 851 Problem Description You are given two strings s1[0..l1], s2[0..l2] and Q - number of queries.Your task

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

hdu3911 线段树 区间合并

1 //Accepted 3911 750MS 9872K 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a documen

【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少.1 ≤ n ≤ 105,1 ≤ m ≤ 105,1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 20 Sample Input 9 9 -8 9 -1 -1 -1 9 -8 9 3 1 1 9 1 1 1 9 2 1 4 6 3 Sample Output 17 25

POJ 3667(线段树区间合并)

http://poj.org/problem?id=3667 题意:两个操作 : 1 选出靠左的长度为a的区间. 2 把从 a到a+b的区间清空. 线段树区间合并+lazy // by caonima // hehe #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; co

hdu4553约会安排(线段树区间合并)

链接 poj3667的加强版 当时的题解 这里只不过对于女神需要另开算,DS的占用的时间不加在女神身上,女神的时间都要加,清空的时候也都要算. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath>

CF 46 D Parking Lot(线段树区间合并)

Description Nowadays it is becoming increasingly difficult to park a car in cities successfully. Let's imagine a segment of a street as long as L meters along which a parking lot is located. Drivers should park their cars strictly parallel to the pav