2957: Building Reconstruction
Time Limit: 10 Sec Memory Limit: 256 MB
Description
There is a large construction site outside the building of Xiao A. There are N buildings to be built on the construction site. Every day, houses on this construction site are demolished, built and demolished. He often looked out of the window in a daze, counting how many houses he could see.
To simplify the problem, we consider that these events occur in a two-dimensional plane. The location of small A at (0,0) points in the plane can be represented by a line connecting (i,0) and (i,Hi), where Hi is the height of the first building. If any point above 0 in the building does not intersect the (0,0) line with the previous line segment, the building is considered visible.
The construction team lasted for A total of M days. Initially, all buildings had not yet been built, and their height was 0. On day i, the building team will change the height of the house with the abscissa of Xi to Yi (the height can be bigger than before - built, smaller than before - demolished, or even kept unchanged - the building team did nothing on that day). How many buildings can he see every day after the construction team is finished?
Input
The first line has two positive integers N,M
Next, line M, with two positive integers per line Xi,Yi
Output
Line M, an integer in line i indicates how many buildings can be seen by A after day i
Sample Input
3 4
2 4
3 6
1 1000000000
1 1
Sample Output
1
1
1
2
Data conventions
For all data 1<=Xi<=N, 1<=Yi<=10^9
N,M<=100000
HINT
Source
China National Team Tsinghua Training Day 2012-2013
/**************************************************************
Problem: 2957
User: Twi_etn
Language: C++
Result: Accepted
Time:2356 ms
Memory:9100 kb
****************************************************************/
/*
Line segment tree approach: For each node of line segment tree, two values are maintained: ans and maxl.
ans Represents an answer that only considers the visual range of the interval, and maxl represents the maximum slope of the interval.
The key to the problem is how to merge the two intervals. Obviously, the answer of the left interval can be used as the answer of the total interval.
Then the next step is to see how many constraints on the right interval are feasible after adding new constraints on the left interval.
Consider that if the maximum value of the right interval is less than or equal to the maximum value of the left interval, then the right interval will not contribute, which is equivalent to being blocked by the whole.
If it is larger than the maximum value, then consider the two sub-intervals of the right interval: the left sub-interval and the right sub-interval.
If the maximum value of the left subinterval is less than or equal to the maximum value of the left subinterval, then the right subinterval is processed recursively.
Otherwise, the left subinterval is processed recursively, and the original answer of the right subinterval is added.
Consider the inevitability of doing so: because adding the highest left interval is shorter than the highest left subinterval.
So it is equivalent to that the left interval has no restriction on the right subinterval, and all the restrictions are generated by the left subinterval.
But the answer to the right sub-interval should be the right sub-interval answer-the left sub-interval answer.
It is not possible to call the right sub-interval's own answer directly, because its own answer does not consider the constraints of the left sub-interval.
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 100010
int n,m;
struct Seg_Tree{ int l,r,sum;double maxk; }tre[MAXN<<2];
void Build(int u,int l,int r){
tre[u].l=l;tre[u].r=r;
if(l==r) return ;
int Mid=(l+r)>>1;
Build(u<<1,l,Mid);Build(u<<1|1,Mid+1,r);
}
int calc(int u,double k){
if(tre[u].l==tre[u].r) return tre[u].maxk>k;
if(tre[u<<1].maxk>k) return calc(u<<1,k)+tre[u].sum-tre[u<<1].sum;
else return calc(u<<1|1,k);
}
inline void UpDate(int u){
tre[u].maxk=max(tre[u<<1].maxk,tre[u<<1|1].maxk);
tre[u].sum=tre[u<<1].sum+calc(u<<1|1,tre[u<<1].maxk);
return;
}
void Change(int u,int pos,double k){
if(tre[u].l==tre[u].r){
tre[u].maxk=k;tre[u].sum=1;
return ;
}
int Mid=(tre[u].l+tre[u].r)>>1;
if(pos<=Mid) Change(u<<1,pos,k);
if(pos>Mid) Change(u<<1|1,pos,k);
UpDate(u);
}
int main(){
scanf("%d%d",&n,&m);
Build(1,1,n);
for(int i=1;i<=m;i++){
double x,y;
scanf("%lf%lf",&x,&y);
Change(1,(int)x,y/x);
printf("%d\n",tre[1].sum);
}
return 0;
}