1. 程式人生 > >bzoj2957 樓房重建(線段樹)

bzoj2957 樓房重建(線段樹)

-- 房子 國家隊 開始 正整數 ont 二維 大於 gre

2957: 樓房重建

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

HINT

Source

中國國家隊清華集訓 2012-2013 第一天

/*
線段樹做法:對於線段樹每個結點維護兩個值:ans和maxl,
ans表示只考慮這個區間的可視區間的答案,maxl表示這個區間的最大斜率。
那麽問題的關鍵就在於如何合並兩個區間,顯然左區間的答案肯定可以作為總區間的答案,
那麽接下來就是看右區間有多少個在新加入左區間的約束後是可行的。
考慮如果右區間最大值都小於等於左區間最大值那麽右區間就沒有貢獻了,相當於是被整個擋住了。
如果大於最大值,就再考慮右區間的兩個子區間:左子區間、右子區間,
加入左子區間的最大值小於等於左區間最大值,那麽就遞歸處理右子區間;
否則就遞歸處理左子區間,然後加上右子區間原本的答案。
考慮這樣做的必然性:因為加入左區間最高的比左子區間最高的矮,
那麽相當於是左區間對於右子區間沒有約束,都是左子區間產生的約束。
但是右子區間的答案要用右區間答案-左子區間答案,
不能直接調用右子區間本身答案,因為其本身答案沒有考慮左子區間的約束。
*/ #include<iostream> #include<algorithm> #include<cstdio> #define N 100010 using namespace std; int n,m; struct node { double mx; int sum,l,r; }tr[N<<2]; void build(int now,int l,int r) { tr[now].l=l;tr[now].r=r; if(l==r) return; int mid=(l+r)>>1; build(now<<1,l,mid);build(now<<1|1,mid+1,r); } int calc(double k,int now) { if(tr[now].l==tr[now].r) return tr[now].mx>k; if(tr[now<<1].mx>k) return calc(k,now<<1)+tr[now].sum-tr[now<<1].sum; else return calc(k,now<<1|1); } inline void pushup(int now) { tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx); tr[now].sum=tr[now<<1].sum+calc(tr[now<<1].mx,now<<1|1); } void change(int now,int pos,double c) { if(tr[now].l==tr[now].r) { tr[now].mx=c; tr[now].sum=1; return; } int mid=(tr[now].l+tr[now].r)>>1; if(pos<=mid) change(now<<1,pos,c); else change(now<<1|1,pos,c); pushup(now); } int main() { scanf("%d%d",&n,&m); build(1,1,n); for(int i=1;i<=m;i++) { double x,y; scanf("%lf%lf",&x,&y); change(1,(int)x,y/x); printf("%d\n",tr[1].sum); } return 0; }

bzoj2957 樓房重建(線段樹)