zoukankan      html  css  js  c++  java
  • 成都磨子桥技工学校 / 数据结构 Challenge 6(楼房重建)

    描述

    给一个长为N的数列,有M次操作,每次操作是以下两种之一:

    (1)修改数列中的一个数

    (2)求数列中有多少个数比它前面的数都大

    题解

    不会就去参考了一下前辈的题解,说是楼房重建的原题,又去参考了楼房重建的题解(滑稽)。

    对于本题,建立线段树,区间记录最大值和有多少数比前面的数都大的数的个数sum。

    考虑合并区间时第二个信息,如果右区间最大值小于等于左区间最大值,那么直接取左区间信息,应该比较显然右区间的任何一个元素都比左区间最大值小。

    不然的话就要把左区间最大值val带入右区间查询,如果现在val>=左区间最大值,那么查询右区间即可;不然进入左区间查询,然后+sum[rt]-sum[ls],为什么可以不查询右区间呢?因为sum已经记录了整个区间的信息,sum[rt]-sum[ls]就是右区间中比前面的数都大的数的个数(对于整个区间),现在val<左区间最大值,所以就是答案。

    如果非要查询val应该就要改成左区间最大值。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    int n,m,cnt;
    int root,ls[maxn<<1],rs[maxn<<1],sum[maxn<<1];
    int h[maxn<<1],a[maxn];
    
    template<class T>inline void read(T &x){
      x=0;int f=0;char ch=getchar();
      while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
      x= f ? -x : x ;
    }
    
    int query(int rt,int l,int r,int val){
      if(l==r) return h[rt]>val;
      int mid=(l+r)>>1;
      if(val>=h[ls[rt]]) return query(rs[rt],mid+1,r,val);
      return query(ls[rt],l,mid,val)+sum[rt]-sum[ls[rt]];
    }
    
    int update(int rt,int l,int r){
      if(h[ls[rt]]>=h[rs[rt]]) return sum[ls[rt]];
      return sum[ls[rt]]+query(rs[rt],((l+r)>>1)+1,r,h[ls[rt]]);
    }
    
    void build(int &rt,int l,int r){
      rt=++cnt;
      if(l==r){
        h[rt]=a[l];
        sum[rt]=1;
        return ;
      }
      int mid=(l+r)>>1;
      build(ls[rt],l,mid);
      build(rs[rt],mid+1,r);
      sum[rt]=update(rt,l,r);
      h[rt]=max(h[ls[rt]],h[rs[rt]]);
    }
    
    void modify(int rt,int l,int r,int pos,int val){
      if(l==r){
        h[rt]=val;
        sum[rt]=1;
        return ;
      }
      int mid=(l+r)>>1;
      if(pos<=mid) modify(ls[rt],l,mid,pos,val);
      else modify(rs[rt],mid+1,r,pos,val);
      sum[rt]=update(rt,l,r);
      h[rt]=max(h[ls[rt]],h[rs[rt]]);
    }
    
    int main(){
      read(n);read(m);
      for(int i=1;i<=n;i++){
        int x;read(x);
        a[i]=x;
      }
      build(root,1,n);
      for(int i=1;i<=m;i++){
        char op[2];
        scanf("%s",op);
        if(op[0]=='Q') printf("%d
    ",sum[1]);
        else {
          int pos,val;
          read(pos);read(val);
          modify(1,1,n,pos,val);
        }
      }
    }
    View Code

    对于楼房重建把每个位置的权值弄成斜率即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    int n,m,cnt;
    int root,ls[maxn<<1],rs[maxn<<1],sum[maxn<<1];
    double h[maxn<<1];
    
    template<class T>inline void read(T &x){
      x=0;int f=0;char ch=getchar();
      while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
      x= f ? -x : x ;
    }
    
    int query(int rt,int l,int r,double val){
      if(l==r) return h[rt]>val;
      int mid=(l+r)>>1;
      if(val>h[ls[rt]]) return query(rs[rt],mid+1,r,val);
      return query(ls[rt],l,mid,val)+sum[rt]-sum[ls[rt]];
    }
    
    int update(int rt,int l,int r){
      if(h[ls[rt]]>=h[rs[rt]]) return sum[ls[rt]];
      return sum[ls[rt]]+query(rs[rt],((l+r)>>1)+1,r,h[ls[rt]]);
    }
    
    void build(int &rt,int l,int r){
      rt=++cnt;
      if(l==r) return ;
      int mid=(l+r)>>1;
      build(ls[rt],l,mid);
      build(rs[rt],mid+1,r);
    }
    
    void modify(int rt,int l,int r,int pos,double val){
      if(l==r){
        h[rt]=val;
        sum[rt]=1;
        return ;
      }
      int mid=(l+r)>>1;
      if(pos<=mid) modify(ls[rt],l,mid,pos,val);
      else modify(rs[rt],mid+1,r,pos,val);
      sum[rt]=update(rt,l,r);
      h[rt]=max(h[ls[rt]],h[rs[rt]]);
    }
    
    int main(){
      read(n);read(m);
      build(root,1,n);
      for(int i=1;i<=m;i++){
        int pos,val;
        read(pos);read(val);
        modify(1,1,n,pos,1.0*val/pos);
        printf("%d
    ",sum[1]);
      }
    }
    View Code

     

  • 相关阅读:
    周鸿祎:很多程序员聪明,但我一看就知道他不会成功
    Ubuntu/centos/redhat/SUSE sipp安装(带rtp支持,3.5.1版本)
    ffmpeg源码分析之媒体打开过程
    搜集的动植物分类、检索网站
    sipp命令 各参数含义
    最简单的一个win32程序
    vi学习笔记
    删除结点 (双向链表)
    插入结点(双向链表)
    La=LaULb (单链表)
  • 原文地址:https://www.cnblogs.com/sto324/p/11380053.html
Copyright © 2011-2022 走看看