樓房重建
阿新 • • 發佈:2018-02-05
log strong 發生 是個 位置 代碼 down 個數 讀者
==\(r\)時,直接看斜率的大小關系
如果暴力尋找的區間,其左兒子的斜率最大值小於記錄斜率,那麽左兒子就啥都看不見,那我們就只關註右兒子
如果左兒子的斜率最大值大於記錄斜率,那麽我們就去暴力查找左兒子。右兒子也要查找嗎?不,因為右兒子一定會被左兒子的斜率最大值所遮擋,所以右兒子所能看到的個數即為\(tree[p]-tree[ls]\)
(ps:有點繞口,讀者們可以邊看代碼,邊理解)
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\)
如果暴力尋找的區間,其左兒子的斜率最大值小於記錄斜率,那麽左兒子就啥都看不見,那我們就只關註右兒子
如果左兒子的斜率最大值大於記錄斜率,那麽我們就去暴力查找左兒子。右兒子也要查找嗎?不,因為右兒子一定會被左兒子的斜率最大值所遮擋,所以右兒子所能看到的個數即為\(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; }
樓房重建