zoukankan      html  css  js  c++  java
  • 洛谷4198 楼房重建(线段树)

    神仙题。pb 说是套路题???

    首先只有楼房顶有用,然后要斜率递增。

    没事干了,上线段树。

    肯定要记录区间单调队列的长度 (len)。当然把整个能看到的位置都记下来会更方便,然而复杂度就爆了。

    顺便再来个区间最大值 (mx)

    修改是单点,叶子很好搞。询问就是根节点的 (len)

    难点就在 pushup。

    (mx) 不管,只看 (len)

    首先发现,最左边的和最大值都能看到。

    pushup 时,首先左边的所有数都仍然能被看到,右边能看到的数的个数和左边的最大值有关,右边留下的只有大于左边最大值的数。

    所以我们递归 pushup:

    参数有:线段树节点编号 (o) 和能看到的数的下界 (lwr)(也就是只保留 (>lwr) 的数,然后再求看不看得到)

    如果 (mx_ole lwr),整个区间都不能看到。

    如果 (a_l>lwr),那么答案就是 (len_o)(能看到的数和没有这个下界没区别)。

    如果 (mx_{lson}le lwr),那么左儿子全都没有,递归到右儿子 (pushup(rson,lwr))

    否则左儿子的最大值肯定保留了下来,那么右儿子能看到的数与没有下界没有区别,个数是 (len_o-len_{lson})。递归到左儿子 (pushup(lson,lwr)+len_o-len_{lson})

    这样 pushup 一次是 (O(log n))

    时间复杂度 (O(mlog^2n))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN=400040;
    #define ls o<<1
    #define rs o<<1|1
    #define lson ls,l,mid
    #define rson rs,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    template<typename T>
    inline void read(T &x){
    	x=0;
    	char ch=getchar();bool f=false;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	if(f) x=-x;
    }
    int n,m,len[MAXN];
    double a[MAXN],mx[MAXN];
    inline void pushup1(int o){
    	mx[o]=max(mx[ls],mx[rs]);
    }
    int pushup2(int o,int l,int r,double lwr){
    	if(a[l]>lwr) return len[o];
    	if(mx[o]<=lwr) return 0;
    	int mid=(l+r)>>1;
    	if(mx[ls]<=lwr) return pushup2(rson,lwr);
    	else return pushup2(lson,lwr)+len[o]-len[ls];
    }
    inline void pushup(int o,int l,int r){
    	pushup1(o);
    	int mid=(l+r)>>1;
    	len[o]=len[ls]+pushup2(rson,mx[ls]);
    }
    void update(int o,int l,int r,int p,double v){
    	if(l==r) return void((mx[o]=v,len[o]=1));
    	int mid=(l+r)>>1;
    	if(mid>=p) update(lson,p,v);
    	if(mid<p) update(rson,p,v);
    	pushup(o,l,r);
    }
    int main(){
    	read(n);read(m);
    	while(m--){
    		int x,y;
    		read(x);read(y);
    		update(1,1,n,x,a[x]=1.0*y/x);
    		printf("%d
    ",len[1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11976014.html
Copyright © 2011-2022 走看看