bzoj 2957 楼房重建(线段树)
2018-03-29 22:18
465 查看
bzoj 2957 楼房重建
这题是集训时讲到的,感觉不错就做了做;
先把每个楼的高度除以xi,这样得到的斜率ki,然后求一个从左往右开始左边优先选的最长上升序列;
首先我想到的做法是,用线段树来维护,每个点存当前区间内合法的那个序列的最小值和最大值以及长度,每次改完一个值一路update上去,update时先把左区间的答案加上去,再在右区间内找一段大于左区间合法序列的最大值的合法序列;
然后查找的时候我犯傻了。。。我是先找左区间,找完再以左区间最大值找右区间,这样t到飞起,复杂度好像n^2*logn?。。。
然后考虑减少重复计算次数,每个点记录lsum和rsum表示从左区间转移来的答案和从右区间转移来的答案
这样查找时如果能从左区间进行查找,那么直接加上右区间既定的答案就好;
否则直接从右区间查找;
这样正确性显然,复杂度nlogn^2
代码:
这题是集训时讲到的,感觉不错就做了做;
先把每个楼的高度除以xi,这样得到的斜率ki,然后求一个从左往右开始左边优先选的最长上升序列;
首先我想到的做法是,用线段树来维护,每个点存当前区间内合法的那个序列的最小值和最大值以及长度,每次改完一个值一路update上去,update时先把左区间的答案加上去,再在右区间内找一段大于左区间合法序列的最大值的合法序列;
然后查找的时候我犯傻了。。。我是先找左区间,找完再以左区间最大值找右区间,这样t到飞起,复杂度好像n^2*logn?。。。
然后考虑减少重复计算次数,每个点记录lsum和rsum表示从左区间转移来的答案和从右区间转移来的答案
这样查找时如果能从左区间进行查找,那么直接加上右区间既定的答案就好;
否则直接从右区间查找;
这样正确性显然,复杂度nlogn^2
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<utility> #define db double #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define mk(a,b) std::make_pair(a,b) #define pr std::pair<int,double> const int maxn=100005; using std::max; struct NODE{ int lsum,rsum; db mv,lv; }t[maxn*4]; db eps=1e-10; bool iszero(db v){ return fabs(v-0.0)<=eps; } pr search(int l,int r,int rt,db v){ if(t[rt].lv-v>eps) return mk(t[rt].lsum+t[rt].rsum,t[rt].mv); if(l==r||t[rt].mv-v<eps)return mk(0,0.0); int mid=(l+r)>>1; int ls=rt<<1; int rs=rt<<1|1; if(t[ls].mv-v>eps){ pr tp=search(lson,v); tp.first+=t[rt].rsum; tp.second=max(tp.second,t[rs].mv); return tp; }else{ return search(rson,v); } } void updata(int rt,int l,int r){ int ls=rt<<1; int rs=rt<<1|1; if(iszero(t[ls].lv)||iszero(t[rs].lv)){ t[rt].lv=t[ls].lv+t[rs].lv; t[rt].mv=max(t[ls].mv,t[rs].mv); t[rt].lsum=t[ls].lsum+t[ls].rsum; t[rt].rsum=t[rs].lsum+t[rs].rsum; return; } int mid=(l+r)>>1; pr tp=search(rson,t[ls].mv); t[rt].lv=t[ls].lv; t[rt].lsum=t[ls].lsum+t[ls].rsum; t[rt].rsum=tp.first; t[rt].mv=max(t[ls].mv,tp.second); } void modify(int l,int r,int rt,int pos,int v){ if(l==r){ t[rt].lsum=0,t[rt].rsum=1,t[rt].lv=t[rt].mv=(db)v/pos; return; } int mid=(l+r)>>1; if(pos<=mid)modify(lson,pos,v); else modify(rson,pos,v); updata(rt,l,r); } int n,m; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int tc,tv; scanf("%d%d",&tc,&tv); modify(1,n,1,tc,tv); printf("%d\n",t[1].lsum+t[1].rsum); } return 0; }
相关文章推荐
- Bzoj 2957: 楼房重建(线段树)
- bzoj 2957: 楼房重建(线段树)
- BZOJ 2957 楼房重建(线段树)(思路)
- BZOJ2957 楼房重建 【线段树】
- bzoj2957: 楼房重建【线段树】
- [bzoj2957][楼房重建] (线段树)
- BZOJ 2957 楼房重建(线段树)(思路)
- BZOJ 2957 楼房重建(线段树)(思路)
- [BZOJ2957]楼房重建-线段树
- BZOJ2957 楼房重建(线段树)
- 【BZOJ】2957 楼房重建 线段树
- BZOJ 2957 楼房重建(线段树)(思路)
- bzoj 2957: 楼房重建 线段树
- BZOJ_2957_楼房重建_线段树
- 【BZOJ2957】楼房重建(线段树)
- BZOJ 2957 楼房重建(线段树)(思路)
- 【bzoj2957】【楼房重建】另类的线段树(浅尝ACM-H)
- bzoj2957 楼房重建 线段树
- bzoj 2957: 楼房重建 线段树维护单调栈
- BZOJ 2957 楼房重建(线段树)(思路)