1. 程式人生 > >樓房重建

樓房重建

log strong 發生 是個 位置 代碼 down 個數 讀者

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
對於所有的數據1<=Xi<=N,1<=Yi<=10^9
N,M<=100000

Output

M行,第i行一個整數表示第i天過後小A能看到的樓房有多少棟

Sample Input
3 4
2 4
3 6
1 1000000000
1 1

Sample Output
1
1
1
2

這題是個線段樹好題
我們記錄區間所能看到的樓房數和區間斜率最大值
為什麽記錄斜率?因為斜率大的會遮住斜率小的
考慮更新?
斜率好說,\(max\)即可
看見的樓房數怎麽更新?
首先左兒子能看到多少個,當前區間就必定能看到多少個。那右邊能看到多少個呢?
暴力尋找,用左兒子的斜率最大值(後文記為“記錄斜率”)放到右兒子中看能看到多少個
\(l\)

==\(r\)時,直接看斜率的大小關系
如果暴力尋找的區間,其左兒子的斜率最大值小於記錄斜率,那麽左兒子就啥都看不見,那我們就只關註右兒子
如果左兒子的斜率最大值大於記錄斜率,那麽我們就去暴力查找左兒子。右兒子也要查找嗎?不,因為右兒子一定會被左兒子的斜率最大值所遮擋,所以右兒子所能看到的個數即為\(tree[p]-tree[ls]\)
(ps:有點繞口,讀者們可以邊看代碼,邊理解)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<‘0‘||ch>‘9‘;ch=getchar())    if (ch==‘-‘)    f=-1;
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())  x=(x<<1)+(x<<3)+ch-‘0‘;
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+‘0‘);
}
const int N=1e5;
struct Segment{
    #define ls (p<<1)
    #define rs (p<<1|1)
    int tree[N*4+10];
    double K[N*4+10];
    int query(int p,int l,int r,double x){
        if (l==r)   return K[p]>x;//當l==r時直接比較
        int mid=(l+r)>>1;
        if (K[ls]<=x)    return query(rs,mid+1,r,x);//左兒子什麽都看不見
        else    return tree[p]-tree[ls]+query(ls,l,mid,x);//右兒子只會被左兒子的斜率最大值所遮擋,所以右兒子能看見的個數即為tree[p]-tree[ls]
    }
    void change(int p,int l,int r,int x,double y){//斜率修改
        if (l==r){
            K[p]=y,tree[p]=1;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid)  change(ls,l,mid,x,y);
        if (x>mid)   change(rs,mid+1,r,x,y);
        K[p]=max(K[ls],K[rs]);//斜率的更新
        tree[p]=tree[ls]+query(rs,mid+1,r,K[ls]);//將左兒子的斜率最大值放到右兒子中去暴力查詢
    }
}Tree;
int main(){
    int n=read(),m=read();
    for (int i=1,x,y;i<=m;i++){
        x=read(),y=read();
        Tree.change(1,1,n,x,1.0*y/x);
        printf("%d\n",Tree.tree[1]);
    }
    return 0;
}

樓房重建