bzoj2957楼房重建——线段树
题目: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; }