1. 程式人生 > >bzoj 2957: 樓房重建

bzoj 2957: 樓房重建

digi 都沒有 施工隊 inline tar color 數量 names isdigit

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 2739 Solved: 1295
[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


具體的操作都在代碼裏。
可以看見的樓房就是一個從左到右斜率單增的序列,所以我們考慮用線段樹合並答案。 (是不是這種需要動態維護一個二維偏序的長度的題都可以用玄學線段樹合並???)
/*
    線段樹合並的題目,mh表示區間最大斜率。
    ans[o]表示只考慮o這個節點的區間可以看到的樓房數(從左到右)
    顯然我們合並的時候,左兒子的ans可以直接合並進來,但是右兒子
    能給父節點的貢獻會<=它的ans,因為可能會有被左兒子樓房擋住的樓房。
    
    那麽我們考慮用calc(o,h)計算出o子樹中斜率>h的節點數量。
    那麽
        if maxheight[leftchild]<=h then 返回 calc(rightchild,h)
        //因為這種情況下左子樹中斜率最大都沒有比h大的,所以直接向右子樹遞歸查找就好了。
        
        else 返回 calc(leftchild,h)+ans[o]-ans[leftchild]
        //這種情況下左右子樹中顯然都會有貢獻,但是因為左子樹中已經有斜率>h的了,
        //所以外層的修改已經對右子樹沒有作用了。
        //顯然右子樹中斜率>左子樹中最大的節點數量是ans[o]-ans[leftchild] 
*/ #include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; double mh[maxn<<2|1],val; int n,m,ans[maxn<<2|1],pos,k; inline int read(){ int x=0;char ch=getchar(); for(;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=x*10+ch-0; return
x; } int calc(int o,int l,int r,double height){ if(l==r) return mh[o]>height; int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; if(mh[lc]<=height) return calc(rc,mid+1,r,height); else return calc(lc,l,mid,height)+ans[o]-ans[lc]; } void update(int o,int l,int r){ if(l==r){ mh[o]=val,ans[o]=1; return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; if(pos<=mid) update(lc,l,mid); else update(rc,mid+1,r); mh[o]=max(mh[lc],mh[rc]); ans[o]=ans[lc]+calc(rc,mid+1,r,mh[lc]); } int main(){ scanf("%d%d",&n,&m); while(m--){ pos=read(),k=read(); val=k/(double)pos; update(1,1,n); printf("%d\n",ans[1]); } return 0; }

bzoj 2957: 樓房重建