zoukankan      html  css  js  c++  java
  • BZOJ 2957 楼房重建

    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;
    }
    
  • 相关阅读:
    Java中的位运算符
    华为2019年NE40E-X8,承诺命令
    华为网络设备修改console密码
    MySQL5.7 多实例
    华为防火墙域间策略全开命令
    Linux基础命令---ntpstat显示时间服务器同步
    【转载】Java程序模拟公安局人员管理系统
    redis cluster集群动态伸缩--删除主从节点
    DBUtils的使用之查询的操作
    服务治理-Resilience4j(限流)
  • 原文地址:https://www.cnblogs.com/mmlz/p/4424741.html
Copyright © 2011-2022 走看看