Description
小A的楼房外有一大片施工工地,工地上有(N)栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
为了简化问题,我们考虑这些事件发生在一个二维平面上。小A在平面上((0,0))点的位置,第i栋楼房可以用一条连接((i,0))和((i,H_{i}))的线段表示,其中(H_{i})为第(i)栋楼房的高度。如果这栋楼房上任何一个高度大于(0)的点与((0,0))的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
施工队的建造总共进行了(M)天。初始时,所有楼房都还没有开始建造,它们的高度均为(0)。在第(i)天,建筑队将会将横坐标为(X_{i})的房屋的高度变为(Y_{i})(高度可以比原来大---修建,也可以比原来小---拆除,甚至可以保持不变---建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房?
Input
第一行两个正整数(N,M)。
接下来(M)行,每行两个正整数(X_{i},Y_{i})。
Output
M行,第i行一个整数表示第(i)天过后小A能看到的楼房有多少栋。
Sample Input
3 4
2 4
3 6
1 1000000000
1 1
Sample Output
1
1
1
2
Hint
数据约定
对于所有的数据(1 le X_{i} le N),(1 le Y_{i} le 10^{9})。
(N,M le 100000)
很早就听说过这一题的大名,却一直没有去写,今天来写一下。
我们用线段树来维护斜率的一条上升的链,(L_{i})表示链左端的斜率,(R_{i})表示链右端的斜率。
考虑如何维护,对于区间(l sim r)一段区间,我们用(l sim mid)这段的右端点,放到(mid+1 sim r)中询问,复杂度(O(nlog^{2}n))。
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define eps (1e-12)
#define maxn 400010
int n,m,len[maxn]; double L[maxn],R[maxn];
inline bool equal(double a,double b) { return fabs(a-b) < eps; }
inline bool dy(double a,double b) { if (equal(a,b)) return false; return a > b; }
inline bool xd(double a,double b) { if (equal(a,b)) return true; return a <= b; }
inline void query(int l,int r,int now,int &k1,double &k2)
{
if (dy(L[now],k2)) k1 += len[now],k2 = R[now];
if (l == r) return;
int mid = (l + r) >> 1;
if (xd(R[now<<1],k2)) query(mid+1,r,now<<1|1,k1,k2);
else
{
query(l,mid,now<<1,k1,k2);
k1 += len[now] - len[now<<1]; k2 = R[now];
}
}
inline void update(int l,int r,int now)
{
len[now] = len[now<<1],L[now] = L[now<<1],R[now] = R[now<<1];
int mid = (l + r) >> 1;
query(mid+1,r,now<<1|1,len[now],R[now]);
}
inline void change(int l,int r,int x,int y,int now)
{
if (l == r) { L[now] = R[now] = 1.0*y/x; len[now] = (y > 0); return; }
int mid = (l + r) >> 1;
if (x <= mid) change(l,mid,x,y,now<<1);
else change(mid+1,r,x,y,now<<1|1);
update(l,r,now);
}
int main()
{
freopen("2957.in","r",stdin);
freopen("2957.out","w",stdout);
scanf("%d %d",&n,&m);
while (m--)
{
int x,y; scanf("%d %d",&x,&y);
change(1,n,x,y,1);
printf("%d
",len[1]);
}
fclose(stdin); fclose(stdout);
return 0;
}