HOJ 2691 Nail III解题报告
2012-02-15 02:48
330 查看
Nail III
墙上有n个钉子,编号为1, 2, …, n。其中钉子i的横坐标为i,纵坐标初始为xi。可以进行如下操作:s t v:若在高度为v处放一块横坐标范围是[s,t]的水平木板,它将下落到什么高度?换句话说,求出钉子s, s+1, s+2, …, t的纵坐标中,不超过v的最大值。如果这些钉子的高度全部大于v,则木板将落到地上,高度为0。注意,在T操作时,水平木板只是用来测试的“临时木板”,将在测试后立即被拿走,不会影响到后续测试工作。
Input
多组case,每组case第一行包含两个整数n(1 ≤ n ≤ 100000), m(1 ≤ m ≤ 50000),即钉子的个数和操作的个数。第二行输入n个整数表示钉子的纵坐标xi(1 ≤ xi ≤ 1000000000);接下来m行询问。这些询问区间之间没有包含关系。Output
为每个询问输出一行,包括一个整数表示询问结果。Sample Input
5 3 1 3 5 7 9 2 4 6 3 5 7 1 2 1
Sample Output
5 7 1
此题是个关于区间询问的题目,数据范围比较大,得选取适当的数据结构。
起初我写的是个线段树,可能是自己写的太差劲了,一直超时。
后来听杨神来讲题解,说这道题用map做,具体的分析如下:
条件中的最后一句说:这些询问区间之间没有包含关系。这是个重要的条件,提示我们可以通过动态的增添维护一个map来查询。每个元素最多添加到map中一次,删除一次,总的复杂度是Nlog(N)级别的。
具体做法如下:
定义一个map,其key值代表高度,另一个值代表钉子的序号。
将区间排序,按照左端点从小到大排序
对于每个区间,讲此区间内未入map的钉子加入进去(这个过程是有序的,因为区间已经排好序)。
调用map的lower_bound函数,查询键值>=key的第一个元素,然后判断它是否在当前查询的区间内,不是的话删除掉,是的话输出
再次将区间排序,按照输入的顺序排
代码如下:
#include <iostream> #include <algorithm> #include <map> #define N 100010 #define M 50010 using namespace std; struct data { int r,l,v,d,b; //r、l分别为区间的左右端点,v为查询的高度,d为输入时的顺序,b为答案 void input(int k) { d=k; scanf("%d %d %d",&r,&l,&v); } }p[M]; int a ; map<int,int>g; bool cmp1(const data a,const data b) //按照区间左端点排序的比较函数 { return a.r<b.r; } bool cmp2(const data a,const data b) //按照输入顺序排序的比较函数 { return a.d<b.d; } int main() { int n,m,i,j,k; while(scanf("%d %d",&n,&m)==2) { for(i=0;i<n;i++) scanf("%d",a+i+1); for(i=0;i<m;i++) p[i].input(i); sort(p,p+m,cmp1); //按照区间左端点排序 g.clear(); map<int,int>::iterator pos; j=1; k=1; for(i=0;i<m;i++) { for(;j<=p[i].l&&j<=n;j++) //将未入map的钉子加入,由于upper_bound返回的是大于等于,所以改成复数加入 g[-a[j]]=j; while(1) { pos=g.lower_bound(-p[i].v); //查询 if(pos==g.end()) //如果没有查到,则木板掉落到地上,输出0 { p[i].b=0; break; } if(pos->second<p[i].r) //如果查到的钉子位置在此区间以前,则删除掉 g.erase(pos); else { p[i].b=-pos->first; //此为查到了区间内第一个小于等于v的钉子 break; } } } sort(p,p+m,cmp2); //按照输入顺序排序 for(i=0;i<m;i++) { printf("%d\n",p[i].b); } } return 0; }
这道题交了好多次,一直Restricted Function,在群里问了下,还以为是超内存了,先前我是把0提前加进去的,没有判断是否是end,现在改成判断是否是end,而不是加入0,就AC了,现在想想,可能是中间某个钉子高度为0,把先前的0冲掉了,使得访问了错误的内存。还是细节问题啊。
PS:我用小号交时,没有完全去掉加入0,而只是多了个end的判断,时间0.60s,排在了第一位,当我去掉0,改用大号交,则变成了0.63s。。。囧。。。很多次了,小号比大号跑得快。。。。
相关文章推荐
- 杭电 HOJ 1016 Prime Ring Problem 解题报告
- HOJ 1003 Max Sum 解题报告
- hoj Secret Message 解题报告
- 杭电 HOJ 1372 Knight Moves 解题报告
- 杭电 HOJ 1426 Sudoku Killer 解题报告
- HOJ 11958 Hyper 解题报告
- HOJ 1003 Max Sum 解题报告
- HOJ 2634 网络流最小割 解题报告
- 杭电 HOJ 2072 单词数 解题报告
- 杭电 HOJ 1455 Sticks 解题报告
- 杭电 HOJ 1548 A strange lift 解题报告
- 杭电 HOJ 1312 Red and Black 解题报告
- HOJ 12058 Judges' Time Calculation 解题报告
- 杭电 HOJ 1394 Minimum Inversion Number 解题报告
- HOJ 3555 Bomb 解题报告
- 杭电 HOJ 1251 统计难题 解题报告
- 杭电 HOJ 1584 蜘蛛牌 解题报告
- 杭电 HOJ 2677 Dota all stars 解题报告
- 杭电 HOJ 2553 N皇后问题 解题报告
- hoj 2473 Fish Can Fly解题报告