题目大意:给定n座楼,初始高度为0,每次可以改变某栋楼的高度,求每次改变高度之后从原点可以看到几栋楼
记录每栋楼楼顶与原点连线的斜率 那么一栋楼可见当且仅当前面所有楼的斜率都小于这栋楼
将n栋楼分为√(0.5*n*logn)块 每一块内维护一个单调上升子序列(注意不是LCS) 比如说4 1 2 3 5 那么维护的序列就是4 5
修改的时候块内暴力重建 然后查询顺着块撸一遍 每次记录当前的最大值 然后去下一个块中二分找到第一个比这个最大值大的值 然后统计答案&&更新最大值
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 #define EPS 1e-10 using namespace std; struct Block{ double elements[1010]; int tot,l,r; void Rebuild(); int Get_Ans(double& x); }blocks[120]; int n,m,b; double a[M]; int belong[M]; void Block :: Rebuild() { int i; double temp=0; tot=0; for(i=l;i<=r;i++) if(a[i]>temp+EPS) temp=a[i],elements[++tot]=a[i]; } int Block :: Get_Ans(double& x) { int re=(tot+1)-(upper_bound(elements+1,elements+tot+1,x+EPS)-elements); if(re) x=elements[tot]; return re; } int main() { int i,j,x,y; cin>>n>>m; b=(int)sqrt(n*log(n)/log(2)/2); for(i=1;(i-1)*b+1<=n;i++) { blocks[i].l=(i-1)*b+1; blocks[i].r=min(i*b,n); } for(i=1;i<=n;i++) belong[i]=(i-1)/b+1; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); a[x]=(double)y/x; blocks[belong[x]].Rebuild(); double temp=0; int ans=0; for(j=1;blocks[j].l;j++) ans+=blocks[j].Get_Ans(temp); printf("%d\n",ans); } return 0; }
原文地址:http://blog.csdn.net/popoqqq/article/details/41957495