码迷,mamicode.com
首页 > 其他好文 > 详细

[题解]luogu_P4198_楼房重建(线段树logn合并

时间:2019-10-03 19:56:09      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:update   ==   node   节点   pre   define   bit   重建   amp   

前言:最近购买了润滑脂和几个个性键帽,润滑脂用的太多大键稍微有点黏,但是我可以接受,钢丝声基本没有了,虽然没有拆下来卫星轴调试,但是效果还是有的,买了一个原厂高度的空格,好看是好看,用料也挺厚,但是形变非常严重,不过三十块要什么自行车,方向键是个手柄按键三角方块啥的透光键帽,用料也还行,但是字符有很明显的凹陷,看不出来但是摸起来就很明显,而且由于灯在轴的上方导致只有上面一半有光能透出来,但是我也不太在意


 

线段树update好题,首先把每个点转化为斜率,这样找一个递增序列即可,但是不同点在于这个递增序列不能挑,看到了就必须看到

这样怎么合并呢?首先对于一个区间左区间肯定全会看到,右区间如果全都矮于左区间最大值那肯定是看不到了,所以先记一个区间最大值,再记一个满足上面要求的区间上升序列长度,

如果右面有比左边大的怎么办呢?我们考虑右区间哪些会被看到,如果右区间的左区间最大值大于左区间的最大值,那么右区间的右区间一定可以全部看到,能看到的内容是右区间最长的合法序列在右区间的右区间的那部分,也就是len(x)-len(ls)

如果右区间的左区间最大值小于左区间的最大值,那么右区间的左区间一定不会被看到,只要去查右区间的右区间即可

#include<bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int maxn=100009;
int n,m;
struct node{
    int len;
    double mx;
}t[maxn<<2];
double a[maxn];
void upd(int x){
    t[x].mx=max(t[ls].mx,t[rs].mx);
}
int find(int x,int l,int r,double lx){
    if(t[x].mx<=lx)return 0;//最大值小于查询的无贡献 
    if(l==r)return a[l]>lx;//叶子节点 
    if(a[l]>lx)return t[x].len;//最左端都大于了全部能看到 
    if(t[ls].mx>lx)return find(ls,l,mid,lx)+t[x].len-t[ls].len;//左区间能看到一部分那么t[x].len在右区间的那部分都能看到,递归查左区间 
    else return find(rs,mid+1,r,lx);
}
void change(int x,int l,int r,int pos,int val){
    if(l==r){
        a[l]=t[x].mx=1.0*val/pos;
        t[x].len=1;
        return;
    }
    if(pos<=mid)change(ls,l,mid,pos,val);
    else change(rs,mid+1,r,pos,val);
    upd(x);
    t[x].len=t[ls].len+find(rs,mid+1,r,t[ls].mx);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,p;i<=m;i++){
        double x;
        scanf("%d%lf",&p,&x);
        change(1,1,n,p,x);
        printf("%d\n",t[1].len);
    }
}

 

[题解]luogu_P4198_楼房重建(线段树logn合并

标签:update   ==   node   节点   pre   define   bit   重建   amp   

原文地址:https://www.cnblogs.com/superminivan/p/11620406.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!