BZOJ 2957 樓房重建
阿新 • • 發佈:2017-07-16
能夠 吐槽 update 重復 node tar 可見 .org 輸入
3 4
2 4
3 6
1 1000000000
1 1
1
1
1
2
數據約定
對於所有的數據1<=Xi<=N,1<=Yi<=10^9
N,M<=100000
題目描述
小A的樓房外有一大片施工工地,工地上有N棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。
為了簡化問題,我們考慮這些事件發生在一個二維平面上。小A在平面上(0,0)點的位置,第i棟樓房可以用一條連接(i,0)和(i,Hi)的線段表示,其中Hi為第i棟樓房的高度。如果這棟樓房上任何一個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麽這棟樓房就被認為是可見的。
施工隊的建造總共進行了M天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫坐標為Xi的房屋的高度變為Yi(高度可以比原來大---修建,也可以比原來小---拆除,甚至可以保持不變---建築隊這天什麽事也沒做)。請你幫小A數數每天在建築隊完工之後,他能看到多少棟樓房?
輸入
第一行兩個正整數N,M
接下來M行,每行兩個正整數Xi,Yi
輸出
M行,第i行一個整數表示第i天過後小A能看到的樓房有多少棟
樣例輸入
3 4
2 4
3 6
1 1000000000
1 1
樣例輸出
1
1
1
2
數據約定
對於所有的數據1<=Xi<=N,1<=Yi<=10^9
N,M<=100000
提示
來源
中國國家隊清華集訓 2012-2013 第一天
吐槽
記得在WC2017day3晚上學線段樹(太菜了,這時候才學線段樹),被同寢室的新疆大佬uncle-lu安利了這道題(他的博客),從WC2017day3拖到NOI2017day0,總算AC了,不容易啊!
NOI前夕突然很想抒發一下內心的情感,但語文不好找不到詞兒………………
原來只要在粘貼的時候末尾空一行,BZOJ獨特的題面格式就能粘上來呀…還別說藍色挺符合我博客的風格……
解題思路
本著不重復造輪子的思想,偷個懶——http://hzwer.com/6746.html,或者上面那個鏈接也行……
源代碼
#include<cstdio> #include<algorithm> intn,m; struct Node{ int l,r; int num;//區間內可見建築數 double maxk;//區間內最大斜率 }t[400010]; void maketree(int x,int l,int r) { t[x]={l,r,0,0.0}; if(l==r) return; int mid=l+r>>1; maketree(x<<1,l,mid); maketree(x<<1|1,mid+1,r); } int calc(int x,double k) { int l=t[x].l,r=t[x].r; if(l==r) return t[x].maxk>k; if(t[x<<1].maxk<=k) return calc(x<<1|1,k); else return t[x].num-t[x<<1].num+calc(x<<1,k); } void update(int x,int pos,double k) { int l=t[x].l,r=t[x].r,mid=l+r>>1; if(l==r) { t[x].num=1; t[x].maxk=k; return; } if(pos<=mid) update(x<<1,pos,k); else update(x<<1|1,pos,k); t[x].maxk=std::max(t[x<<1].maxk,t[x<<1|1].maxk); t[x].num=t[x<<1].num+calc(x<<1|1,t[x<<1].maxk); } int main() { scanf("%d%d",&n,&m); maketree(1,1,n); int x,y; while(m--) { scanf("%d%d",&x,&y); update(1,x,(double)y/x); printf("%d\n",t[1].num); } return 0; }
BZOJ 2957 樓房重建