当前位置:
首页 >
P4198-楼房重建【线段树】
发布时间:2023/12/3
59
豆豆
生活随笔
收集整理的这篇文章主要介绍了
P4198-楼房重建【线段树】
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
正题
题目链接:https://www.luogu.com.cn/problem/P4198
题目大意
nnn条线,开始时第iii条是(i,0)(i,0)(i,0)的一个点。
每次有操作把第xxx条线变成(x,0)(x,0)(x,0)到(x,y)(x,y)(x,y)。然后求从(0,0)(0,0)(0,0)能看到几条线。
解题思路
把线变成斜率的话就是对于每个点求一个往后比它大的第一个点然后一直跳来做了。
线段树的话主要是合并区间的时候比较麻烦,一个暴力的想法是直接维护每个区间的序列,然后合并的时候一个在另一个上面二分,但是这样合并的复杂度是O(len)O(len)O(len)的。
发现我们需要的只是在右区间的序列上二分而已,而右区间的序列是由它线段树上的子树得到,所以我们没有必要真正的存下来维护的序列,可以直接在右边的线段树上二分。
大概的操作就是右边分出来的左右两个区间,如果左边的区间最大值要比目前的值要小,那么左边区间没有贡献,直接到右边。否则那么这样跳一定会到达左边区间的最大值,然后就是递归求右边区间的答案,这部分答案我们已经处理完了,直接累加然后递归作左区间即可。
这样时间复杂度就是O(nlog2n)O(n\log^2 n)O(nlog2n)的了
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+10; int n,m,len[N<<2]; double w[N<<2],a[N]; int PushUp(double val,int x,int L,int R){if(w[x]<=val)return 0;if(L==R)return a[L]>val;int mid=(L+R)>>1;if(w[x*2]<=val)return PushUp(val,x*2+1,mid+1,R);return len[x]-len[x*2]+PushUp(val,x*2,L,mid); } void Change(int x,int L,int R,int pos,double val){if(L==R){w[x]=a[L]=val;len[x]=1;return;}int mid=(L+R)>>1;if(pos<=mid)Change(x*2,L,mid,pos,val);else Change(x*2+1,mid+1,R,pos,val);w[x]=max(w[x*2],w[x*2+1]);len[x]=len[x*2]+PushUp(w[x*2],x*2+1,mid+1,R); } int main() {scanf("%d%d",&n,&m);while(m--){int x,y;scanf("%d%d",&x,&y);Change(1,1,n,x,(double)y/x);printf("%d\n",len[1]);}return 0; }总结
以上是生活随笔为你收集整理的P4198-楼房重建【线段树】的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: P6222-「P6156 简单题」加强版
- 下一篇: P5607-[Ynoi2013]无力回天