zoukankan      html  css  js  c++  java
  • 【题解】楼房重建

    Problem

    ( ext{Solution:})

    分析题目,我们看不到一个房子,当且仅当它的斜率严格不大于前面的房子斜率。

    题目让我们求的就是:强制选择出严格单调递增的序列长度最大值,全局询问,单点修改。

    看着很线段树,但是区间的信息怎么去合并呢?

    开始的思路:首先长度必须要维护,然后维护一个最大值,这样合并的时候如果右边最大值小于等于左边的就可以直接跳过了。但是剩下的部分怎么维护?

    忽略掉了线段树的本质:分治。

    我们可以将右区间划分为两个区间来降低问题复杂度。它被我们分成左右两个区间后:

    若被划分左区间的最大值要大于当前需要大于的值,我们就去递归左区间,拼接上右边的答案:(len[x]-len[ls[x]].) 注意不是 (len[rs[x]]) 是因为有些右区间的值在整体计算的时候是不能被计算的。

    那么如果被划分的左区间最大值小于等于当前需要大于的值,我们就跳过左区间直接去右区间。

    这样,我们通过分治成功将问题规模缩小一半,进行一次更新的复杂度是 (O(log n).)

    于是总复杂度就是:(O(mlog^2 n).)

    关于精度问题:我用 ( ext{long double}) 才卡过去。不知道有没有什么好方法,欢迎指教。

    有很多细节:比如 pushup 函数实现的时候,需要大于的那个值是不需要改变这个参数的。每次我们都进入一个新区间去计算它,但需要大于的值没有变。

    建树的时候由于没有任何一座楼房,所以 len 应该初始成 (0.)

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=4e5+10;
    int ls[MAXN],rs[MAXN],tot,n,m;
    int L[MAXN],R[MAXN],rt,len[MAXN];
    long double maxn[MAXN]; 
    const long double eps=1e-12;
    inline long double Max(long double x,long double y){return x-y>eps?x:y;}
    inline void pushupmax(int x){maxn[x]=Max(maxn[ls[x]],maxn[rs[x]]);}
    inline int pushup(long double v,int x){
    	if(maxn[x]<=v)return 0;
    	if(L[x]==R[x]){
    		if(maxn[x]>v)return 1;
    	}
    	int s1=ls[x],s2=rs[x];
    	if(maxn[s1]<=v)return pushup(v,s2);
    	else{
    		return pushup(v,s1)+len[x]-len[s1];
    	}
    }
    void build(int &x,int l,int r){
    	x=++tot;
    	L[x]=l;R[x]=r;
    	if(l==r){
    		maxn[x]=0;
    		len[x]=0;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(ls[x],l,mid);
    	build(rs[x],mid+1,r);
    	pushupmax(x);
    	len[x]=len[ls[x]]+pushup(maxn[ls[x]],rs[x]);
    }
    void change(int x,int l,int r,long double v){
    	if(L[x]==R[x]){
    		maxn[x]=v;
    		len[x]=1;
    		return;
    	}
    	int mid=(L[x]+R[x])>>1;
    	if(l<=mid)change(ls[x],l,r,v);
    	if(mid<r)change(rs[x],l,r,v);
    	pushupmax(x);
    	len[x]=len[ls[x]]+pushup(maxn[ls[x]],rs[x]); 
    }
    int main(){
    	//freopen("P4198_5.in","r",stdin);
    	//freopen("My.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	build(rt,1,n);
    	for(int i=1;i<=m;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		change(rt,x,x,(long double)(1.0*y/x));
    		printf("%d
    ",len[rt]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    note 11 字典
    note10 元组
    hibernate环境搭建及操作
    JAVA中解决Filter过滤掉css,js,图片文件等问题
    过滤器
    MySQL存储过程(转)
    用java调用oracle存储过程总结(转)
    Oracle分页查询语句的写法(转)
    数据访问类的封装
    事务的特性及事务的隔离级别(转)
  • 原文地址:https://www.cnblogs.com/h-lka/p/14931027.html
Copyright © 2011-2022 走看看