题目链接:https://vjudge.net/problem/HYSBZ-2957
参考来自: https://www.cnblogs.com/kirito520/p/5945427.html
解题思路:
①当前房子能被看见当且仅当之前所有房子的斜率都比当前房子斜率小。(这个人是从(0,0)仰视着看的)
②考虑暴力,修改O(1),查询则O(N)遍历。复杂度 就是 N^2
这个O(N)遍历的具体操作就是记录之前最大斜率,判断当前点能否被看见。
③使用分块,分成T块。
抠出每个块对于这个块来说可见的房子的斜率,斜率是递增的。
那么对于每一次修改,维护每个块内这段递增的斜率的复杂度是O(N/T)
每一次询问,只要二分搜索当前块内比之前所有房子的最大斜率kmax还大的位置就行,所以复杂度为O(T*log(N/T))
通过增加每次询问的时间维护块内信息,使得查询的时候时间大大减少。
代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
#define debug(x) printf("----Line%s----\n",#x)
#define ll long long
#define pb push_back
using namespace std;
const int N = 1e5+5;
const int M = 400;///const int M = sqrt(N)+5 会报错很奇怪
int bl[N],blo,n;
double k[N];
vector<double>ve[M];
void update(int x,int y)
{
k[x] = y*1.0/x;
int pos = bl[x];
ve[pos].clear();
double kmax = 0;
for (int i=blo*(pos-1)+1;i<=min(n,blo*pos);i++){
if (k[i]>kmax) ve[pos].pb(k[i]),kmax = k[i];
}
}
void query()
{
double kmax = 0;
int ans = 0;
for (int i=1;i<=bl[n];i++){
ans = ans + (ve[i].end()-upper_bound(ve[i].begin(),ve[i].end(),kmax));
if (!ve[i].empty()) kmax = max(kmax,ve[i][ve[i].size()-1]);
}
printf("%d\n",ans);
}
int main()
{
int m;
while (~scanf("%d %d",&n,&m)){
memset(k,0,sizeof k);
blo = sqrt(n);
for (int i=1;i<=n;i++) bl[i] = (i-1)/blo + 1;
for (int i=1;i<=bl[n];i++) ve[i].clear();
int x,y;
while (m--){
scanf("%d %d",&x,&y);
update(x,y);
query();
}
}
return 0;
}