题目大意:一个人站在(0,0)处,每次操作都会改变一栋楼的高度,问每次操作之后这个人会看到多少栋楼。
思路:将所有楼分块,在每一块内暴力维护一个单调递增的序列,这样只要这个块中的一栋楼能被看到,那么这一块内能被看到的楼肯定是一段,这样方便统计。
至于是哪一段,二分就可以了。
CODE:
#define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define SIZE 2010 #define EPS 1e-10 using namespace std; #define max(a,b) ((a) > (b) ? (a):(b)) int points,asks; int size,blocks; int belong[MAX],start[MAX],_end[MAX]; double k[MAX]; struct Block{ double stack[SIZE]; int top,p; void Maintain() { top = 0; double _max = .0; for(int i = start[p]; i <= _end[p]; ++i) if(k[i] > _max + EPS) _max = stack[++top] = k[i]; } int GetAns(double _max) { return top - (upper_bound(stack + 1,stack + top + 1,_max + EPS) - stack) + 1; } }block[SIZE]; inline int GetAns() { double _max = .0; int re = 0; for(int i = 1; i <= blocks; ++i) { re += block[i].GetAns(_max); _max = max(_max,block[i].stack[block[i].top]); } return re; } int main() { cin >> points >> asks; size = sqrt(points); for(int i = 1; i <= points; ++i) { belong[i] = i / size + 1; if(!start[belong[i]]) start[belong[i]] = i; _end[belong[i]] = i; } blocks = belong[points]; for(int i = 1; i <= blocks; ++i) block[i].p = i; for(int x,y,i = 1; i <= asks; ++i) { scanf("%d%d",&x,&y); k[x] = (double)y / x; block[belong[x]].Maintain(); printf("%d\n",GetAns()); } return 0; }
时间: 2024-10-09 13:21:05