2957: 楼房重建
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 692 Solved: 327
[ Submit][ Status][ Discuss]
Description
小A的楼房外有一大片施工工地,工地上有N栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
为了简化问题,我们考虑这些事件发生在一个二维平面上。小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度可以比原来大---修建,也可以比原来小---拆除,甚至可以保持不变---建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房?
Input
第一行两个正整数N,M
接下来M行,每行两个正整数Xi,Yi
Output
M行,第i行一个整数表示第i天过后小A能看到的楼房有多少栋
Sample Input
3 4
2 4
3 6
1 1000000000
1 1
Sample Output
1
1
1
2
数据约定
对于所有的数据1<=Xi<=N,1<=Yi<=10^9
N,M<=100000
思路:每一块维护从这一块开头开始的最长上升序列,查询的时候,对于两头的暴力,中间的二分查找,修改的时候直接暴力修改
刚开始我分成了sqrt(N)块,不知道为什么一直RE,分成0.5*n*logn就AC了
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
const double eps=1e-6;
const int maxm=210;
int N,M;
int size;
int num[maxn];
double height[maxn];
double block[maxm][maxm*10];
void change(int x,int y)
{
int x_pos=x/size;
height[x+1]=(double)y/(x+1);
num[x_pos]=0;
double maxv=0;
for(int i=x_pos*size+1;i<=min(N,(x_pos+1)*size);i++)
if(height[i]>maxv)block[x_pos][++num[x_pos]]=height[i],maxv=height[i];
}
void query()
{
int ans=0;
double maxv=0;
for(int i=0;i<=(N-1)/size;i++)
{
if(num[i]==0)continue;
ans+=num[i]+1-(upper_bound(block[i]+1,block[i]+num[i]+1,maxv)-block[i]);
maxv=max(maxv,block[i][num[i]]);
}
printf("%d\n",ans);
}
int main()
{
int x,y;
scanf("%d%d",&N,&M);
size=(int)sqrt(N*log(N)/log(2.0)/2);
memset(height,0,sizeof(height));
memset(num,0,sizeof(num));
while(M--)
{
scanf("%d%d",&x,&y);
if(N==1)
{
if(y)printf("1\n");
else printf("0\n");
continue;
}
x--;
change(x,y);
query();
}
return 0;
}