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

bzoj2957樓房重建——線段樹

bzoj ons include HR scan geo add style print

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957

線段樹維護原點到樓頂的斜率,可以知道答案就是從原點開始斜率遞增的個數;

記錄一個mx數組表示這一段上最大的斜率,二分,分類討論,遞歸求解;

而且如果要取rs的長度,不是直接取tr[rs],而是總長度減去tr[ls],因為不能從右邊一段的起點開始……

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const MAXN=100005;
int
n,m,tr[MAXN<<2]; double xl[MAXN],mx[MAXN<<2]; int find(int x,int l,int r,double w) { if(l==r)return xl[l]>w; int ls=(x<<1),rs=(x<<1|1); int mid=((l+r)>>1); if(mx[ls]>w)return tr[x]-tr[ls]+find(ls,l,mid,w); return find(rs,mid+1,r,w); } void pushup(int
x,int l,int r) { int mid=((l+r)>>1); int ls=(x<<1),rs=(x<<1|1); if(mx[ls]>=mx[rs])tr[x]=tr[ls],mx[x]=mx[ls]; else if(mx[ls]<xl[mid+1])tr[x]=tr[ls]+tr[rs],mx[x]=mx[rs]; else { tr[x]=tr[ls]+find(rs,mid+1,r,mx[ls]); mx[x]=mx[rs]; } }
void add(int nw,int L,int R,int l,int r,double w) { if(l==r) { tr[nw]=1;mx[nw]=w;//!!!註意別把nw寫成l return; } int mid=((l+r)>>1); if(mid>=L)add(nw<<1,L,R,l,mid,w); if(mid<R)add(nw<<1|1,L,R,mid+1,r,w); pushup(nw,l,r); } int main() { scanf("%d%d",&n,&m); for(int i=1,x;i<=m;i++) { double y; scanf("%d%lf",&x,&y); xl[x]=y/x; add(1,x,x,1,n,xl[x]); printf("%d\n",tr[1]); } return 0; }

bzoj2957樓房重建——線段樹