zoukankan      html  css  js  c++  java
  • [BZOJ2957] 楼房重建 (线段树,递归)

    题目链接


    Solution

    经典的一道线段树题,难点在于如何合并节点.
    由于题目要求直线要求不相交,则斜率均大于前面的点即为答案.
    所以以斜率为权值.
    考虑线段树每一个节点维护两个值:

    • (Max) 代表当前节点中的最大值.
    • (Sum) 代表对于任意一个节点 (i) , 其中满足(w_j>Max(w_{l[i]},w_{l[i]+1}...,w_{r[i]}))的个数,其中 (l[i]),(r[i]) 指节点 (i) 所在的区间左右端点.(w)为斜率.

    每一次插入一个节点,它仅会对沿途的最大值和答案产生影响.
    然后每次将已经统计好左儿子的 (Max) 加入与右儿子中的答案进行比较,递归完成整棵线段树.
    然后详情可以看代码.

    Code

    #include<bits/stdc++.h>
    #define N 100008
    using namespace std;
    
    struct node{double max;int sum;}sgm[N*4];
    int n,m,x,k;
    
    int Calc(int node,double maxn,int l,int r)
    {
        int mid=(l+r)>>1;
        if (l==r) return sgm[node].max>maxn;
        if (sgm[node].max<=maxn) return 0;
        //如果当前节点最大值均已不能统计,直接返回.
        if (sgm[node<<1].max<=maxn) return Calc(node<<1|1,maxn,mid+1,r);
        else return sgm[node].sum-sgm[node<<1].sum+Calc(node<<1,maxn,l,mid);
    }
    
    void Update(int node,int l,int r,int x,double k)
    {
        if (l==r)
        {
            sgm[node].max=k;
            sgm[node].sum=1;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid) Update(node<<1,l,mid,x,k);
        else Update(node<<1|1,mid+1,r,x,k);
        sgm[node].max=max(sgm[node<<1].max,sgm[node<<1|1].max);
        sgm[node].sum=sgm[node<<1].sum+Calc(node<<1|1,sgm[node<<1].max,mid+1,r);
        //左边已经处理完,逐层递归返回
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1; i<=m; ++i)
        {
            scanf("%d%d",&x,&k);
            Update(1,1,n,x,k*1.0/x);
            printf("%d
    ",sgm[1].sum);
        }
    }
    
    
    
  • 相关阅读:
    多轨车皮编序问题
    [Luogu1032] 字串变换
    [POJ1101] The Game
    Linux 下源码编译FFMEG
    交叉编译 tcpdump
    现代电视原理-电视传像原理
    Dos:‘锘緻echo’ 不是内部或外部命令,也不是可运行的程序或批处理文件
    Win7 登入壁纸修改
    Office 2016安装后的优化设置
    Linux 系统目录结构
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9738942.html
Copyright © 2011-2022 走看看