zoukankan      html  css  js  c++  java
  • 题解 lg4198 楼房重建--线段树

    lg P4198 楼房重建

    题意

    求一个带修改序列的最大单调上升子序列的长度

    题外话

    我最开始以为只是一座楼房比另一个楼房高就可以看到,但实际上这是无比错误的.

    在图上画画图就可以明白

    序列里面是斜率!!!

    思路

    带了修改,有区间,考虑用线段树来维护

    对于一个区间 (x) ,我们维护 (len)(maxn) 分别代表从这个区间开头的最大单调上升子序列长度区间最大值

    维护(maxn)很简单,所以着重考虑的是(len)

    对于一个区间 (x) ,设其左右区间为 (lc(x)) , (rc(x)),左区间的 (len) 显然可以作为(len[x])的答案组成,接着考虑右区间,若 (maxn[lc(x)]leq maxn[rc(x)]),右区间就没有贡献了

    否则对右区间继续考虑,只有 (maxn[lc(rc(x))]> maxn[lc(x)]) 右区间的左子区间才会有贡献,此时右区间的右子区间只有在(maxn[rc(rc(x))]>maxn[lc(rc(x))])才会有贡献;当(maxn[lc(rc(x))]leq maxn[lc(x)]),此时右区间的右子区间只有在(maxn[rc(rc(x))]>maxn[lc(x)])才会有贡献,这样可以递归下去直到单点,最后统计贡献.以上稍微想想模拟一下就可以明白了.

    但有个问题,对于只有 (maxn[lc(rc(x))]> maxn[lc(x)]) 右区间的左子区间才会有贡献,此时右区间的右子区间只有在(maxn[rc(rc(x))]>maxn[lc(rc(x))])才会有贡献这种情况,你会发现两边都要递归,那么上限会是(O(n))!!!.不过不急,思考一下(len)的意义,你会发现右区间的右子区间的贡献可以通过(len[rc(x)]-len[lc(rc(x))])算出不是

    查询就直接在根节点上查,这样我们就得到了一个(O(nlog_{2}^{2}n))的优秀算法

    代码

    #include<bits/stdc++.h>
    using namespace std;
    int const MAXN=1e5+10;
    int n,m;
    struct SegmentTree{
    	#define lc(x) x<<1
    	#define rc(x) x<<1|1
    	int len[MAXN<<2],l[MAXN<<2],r[MAXN<<2];
    	double maxn[MAXN<<3];
    	void build(int x,int L,int R){
    		l[x]=L,r[x]=R;
    		if(L==R)return;
    		int mid=(L+R)>>1;
    		build(lc(x),L,mid);
    		build(rc(x),mid+1,R);
    	}
    	int find(int x,double h){
    		if(l[x]==r[x]){
    			if(maxn[x]>h)return 1;
    			return 0;
    		}
    		int sum=0;
    		if(maxn[lc(x)]>h){
    			sum+=find(lc(x),h)+len[x]-len[lc(x)];
    		}else if(maxn[rc(x)]>h){
    			sum+=find(rc(x),h);
    		}
    		return sum;
    	}
    	void pushup(int x){
    		maxn[x]=max(maxn[lc(x)],maxn[rc(x)]);
    		len[x]=len[lc(x)];
    		if(maxn[rc(x)]>maxn[lc(x)]){
    			len[x]+=find(rc(x),maxn[lc(x)]);
    		}
    		return;
    	}
    	void insert(int x,int L,int R,int p,int a){
    		l[x]=L,r[x]=R;
    		if(l[x]==r[x]){maxn[x]=(double)a/(double)p,len[x]=1;return;}
    		int mid=(L+R)>>1;
    		if(p<=mid)insert(x<<1,L,mid,p,a);
    		else insert(x<<1|1,mid+1,R,p,a);
    		pushup(x);
    	}
    }Tree;
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		Tree.insert(1,1,n,x,y);
    		printf("%d
    ",Tree.len[1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Configuration Management
    Android Hooking
    技术趋势总结
    Maven Repo Mirror
    拥抱JAVA
    NPM 更新所有依赖项
    Knockout Mvc Compoment FrameSet With Typescript
    Knockoutjs Component问题汇总
    前端编码规范文档
    优秀程序设计的18大原则
  • 原文地址:https://www.cnblogs.com/fpjo/p/13881612.html
Copyright © 2011-2022 走看看