【线段树】BZOJ2957[楼房重建]题解
2018-01-12 10:34
344 查看
题目概述
ZigZagK在 (0,0) ,有 n 座建筑(刚开始高度为 0 )和 m 次改造:把第 i 个建筑高度改为 y ,求每次改造后ZigZagK能看见的建筑数量。解题报告
吃我分块。这好像是套路题?显然就是要求斜率变大的次数。用线段树维护建筑高度,然后定义一个函数 Find(p,k) 表示在 p 节点前放一个斜率 k 得到的斜率变大的次数。
接下来考虑 p 的左儿子 L(p) 中最大的高度 MAX :
MAX≤k :左儿子没用了QAQ,答案为 Find(R(p),k) 。
MAX>k :Find(L(p),k)+Find(R(p),MAX) 。
会发现这样效率很不对,而当 MAX>p 时,右边永远是 MAX ,所以我们在维护 MAX 的同时维护右边的答案就可以保证效率了。时间复杂度 O(nlog22n) 。
示例程序
#include<cstdio> #include<algorithm> using namespace std; typedef long double DB; const int maxn=400000; int n,m,l[maxn+5],r[maxn+5],len[maxn+5]; DB MAX[maxn+5]; #define LS (p<<1) #define RS (p<<1|1) void Build(int L,int R,int p=1){ l[p]=L;r[p]=R;if (L==R) return;int mid=L+(R-L>>1); Build(L,mid,LS);Build(mid+1,R,RS); } int Find(int p,DB k){ if (l[p]==r[p]) return k<MAX[p]; if (MAX[LS]<=k) return Find(RS,k); else return Find(LS,k)+len[p]-len[LS]; } inline void Pushup(int p) {MAX[p]=max(MAX[LS],MAX[RS]);len[p]=len[LS]+Find(RS,MAX[LS]);} void Update(int pos,DB k,int p=1){ if (l[p]==r[p]) {len[p]=1;MAX[p]=k;return;}int mid=l[p]+(r[p]-l[p]>>1); if (pos<=mid) Update(pos,k,LS); else Update(pos,k,RS);Pushup(p); } int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); for (scanf("%d%d",&n,&m),Build(1,n);m;m--){ int x,y;scanf("%d%d",&x,&y);Update(x,(DB)y/x); printf("%d\n",len[1]); } return 0; }
相关文章推荐
- [bzoj2957]楼房重建 线段树
- BZOJ 2957 楼房重建(线段树)(思路)
- 中国国家队清华集训 2012-2013 第一天 BZOJ 2957 楼房重建 线段树题解
- BZOJ 2957: 楼房重建 [线段树 信息合并]
- BZOJ 2957 楼房重建(线段树)(思路)
- bzoj 2957: 楼房重建【线段树】
- BZOJ 2957 楼房重建(线段树)(思路)
- Bzoj 2957: 楼房重建(线段树)
- bzoj 2957 楼房重建(线段树)
- BZOJ 2957 楼房重建(线段树)(思路)
- [BZOJ2957]楼房重建(线段树)
- 【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护
- [bzoj2957][楼房重建] (线段树)
- BZOJ 2957 楼房重建(线段树)(思路)
- bzoj2957楼房重建(线段树)
- BZOJ2957 楼房重建(线段树)
- 【BZOJ】2957 楼房重建 线段树
- BZOJ 2957 楼房重建(线段树)(思路)
- [bzoj2957][线段树]楼房重建
- 【bzoj2957】【楼房重建】另类的线段树(浅尝ACM-H)