首页 > 其他分享 >2023.8.6

2023.8.6

时间:2023-08-06 18:56:54浏览次数:60  
标签:p1 int 最大值 len 序列 区间 2023.8

日常做题

1. P4198 楼房重建

非常离谱的线段树题,反正我当时看了标签是想不出来怎么线段树的。题意就是求斜率单调上升的序列长度(以下简称该序列为答案序列)。好,我们尽力地去想一下线段树怎么做。同样记左区间、右区间节点为 \(p1, p2\) ,我们考虑维护区间的答案长度, 记为 \(len\) 。很快就会发现,合并起来非常难搞,貌似只有O(n)的复杂度做法。这时,我们就尝试着再多维护一个值:区间斜率最大值,记为 \(v\) 。同时我们也可以观察到,显然,两个区间合并时,左区间的答案序列必定是会保留的。那么,我们现在处理右区间就好了。若右区间的最大值小于等于左区间的最大值,那么很明显,右区间的答案序列必然无法对总的答案产生贡献。而当右区间的最大值大于左区间的最大值时,我们就试着递归处理, 求出右区间可以保留的答案序列(此时以下的区间均为目前区间的子区间,即意味着的以下的 \(v, len\)均已知):

传入左区间最大值, 记为 \(lmax\)。

  1. 当 \(l == r\) 时,直接返回 \(v > lmax\) 的值即可。
  2. 当当前区间的左区间最大值小于等于 \(lmax\) 时,直接在右区间递归即可。
  3. 当当前区间的左区间最大值大于 \(lmax\) 时,这个时候,右区间的答案我们就可以直接O(1)算出来了:\(len - p1.len\)。既然左区间的 \(v\) 已经大于 \(lmax\) ,那么右区间的答案序列不就都可以保留嘛,那么它的长度就是 \(len - p1.len\) 。因此只需再在左区间递归即可。

容易证明,此操作的复杂度为 \(O(log n)\),加上线段树查询的复杂度,最后就是 \(O(n log^2n)\) 。

code:

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define N 100010
#define p1 p * 2
#define p2 p * 2 + 1
#define tl tree[p].l
#define tr tree[p].r

struct xds{
  int l, r;
  double v;
  int len;
}tree[N * 4];

int n, m;

int l(int p, double mv){                            //查找区间p中斜率大于mv的单调上升序列长度
  if(tree[p].v <= mv) return 0;
  if(tl == tr){
    return tree[p].v > mv;
  }
  if(tree[p1].v <= mv) return l(p2, mv);           
  return l(p1, mv) + tree[p].len - tree[p1].len;
}

void pushup(int p){
  tree[p].v = max(tree[p1].v, tree[p2].v);
  tree[p].len = tree[p1].len + l(p2, tree[p1].v);
}

void build(int p, int l, int r){                    //建树
  tl = l, tr = r;
  if(l == r){tree[p] = {l, r, 0, 0}; return ;}      //注意:刚开始区间长度不能设为1
  int mid = l + r >> 1;
  build(p1, l, mid);
  build(p2, mid + 1, r);
  pushup(p);
}

void change(int p, int x, int y){                       //修改的同时返回答案
  // cout << p << " " << x << " " << y << endl;
  if(tl == tr){tree[p].v = (double) y / x, tree[p].len = 1; return ;}     //直到修改时才能把区间长度设为1
  int mid = tl + tr >> 1;
  if(x <= mid) change(p1, x, y);
  else change(p2, x, y);
  pushup(p);
  // cout << p << " " << x << " " << y << " " << tree[p].v << " " << tree[p].len << endl;
}

int main(){
  freopen("shuju.in", "r" ,stdin);
  freopen("shuju.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  build(1, 1, n);
  while(m--){
    int x, y;
    cin >> x >> y;
    change(1, x, y);
    cout << tree[1].len << endl;
  }
  return 0;
}

标签:p1,int,最大值,len,序列,区间,2023.8
From: https://www.cnblogs.com/yduck/p/17609418.html

相关文章

  • 【比赛·总结】2023.8 学而思Z6模拟赛
    2023.8学而思Z6模拟赛考试界面:(隐藏)题解反思在本次考试中,作者惨遭爆零。警钟长鸣\(3\)分钟。作者认为,爆零的主要原因在于作者并没有遵从“遇到难题则跳过”的原则,疯狂卡在第一题上,从第\(0\)分钟一直到最后\(1\)秒,除了其中写了一个第二题的暴力,还因为读错题没得分以外,其......
  • 2023.8.4
    P4513小白逛公园求区间的最大子段和。一眼线段树题。那么我们考虑对于线段树的每个节点应该怎么维护:对于每个节点,额外设几个变量:sum,ml,mr,ms,分别表示区间和、包含左端点的最大子段和,包含右端点的最大子段和,最大子段和。我们用p1,p2来表示左儿子和右儿子。ms的维护:......
  • 2023.8.5 周六:DDL--操作表
    1#查询当前数据库的所有表2showtables;34#查询表的结构5descfunc(表的名称);67#创建表注:最后一行不加逗号8creattable表名9(10字段名1,数据类型1,11字段名2,数据类型2,12...13...14字段名n,数据类型n15);1617例,要创......
  • 2023.7.31-2023.8.6暑假第四周博客
     2023.7.31一键启动脚本启动:$HADOOP_HOME/sbin/start-yarn.sh• 从 yarn-site.xml 中读取配置,确定 ResourceManager 所在机器,并启动它• 读取 workers 文件,确定机器,启动全部的 NodeManager• 在当前机器启动 ProxyServer (代理服务器)关闭$HADOOP_HOME/sbin/stop-yar......
  • 2023.8.4
    学习java中的类面向对象与面向过程面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象:强调具备了功能的对象,以类/对象为最小单位类与对象的关系类:对一类事物的描述,是抽象的、概念上的定义对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)面向对象......
  • 2023.8.5
    学习java中的类面向对象与面向过程面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象:强调具备了功能的对象,以类/对象为最小单位类与对象的关系类:对一类事物的描述,是抽象的、概念上的定义对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)面向对象......
  • 2023.8.4 杂题
    1.P5344【XR-1】逛森林先用并查集维护连通性。考虑如何建立传送门:如果使用树剖,强行线段树优化建图,那么空间开销过大,已经有2只\(\log\)。考虑使用倍增优化建图,对于一个点向上\(2^k\)的祖先的形成链都建一个点,模仿LCA的过程建边,空间是1只\(\log\).如果我们模仿ST......
  • 暑假集训D11 2023.8.4 补题
    题意给定一个数组\(a\).询问区间\([l,r]\)是否可以分成\(k\)段,每一段的和都是\(2\)的倍数(偶数)考虑前缀和\(sum\),如果\(sum[i]-sum[j-1]\)是偶数,那么\([j,i]\)一定是\(1\)个合法的区间.因此对于询问\(l,r\),可以统计前缀和的值为偶数的个数,......
  • 2023.8.2
    考完科三临时决定去海边啦十二点半睡四点半起来!!但是居然起得来在学校上课肯定是起不来的但是为了玩是肯定起得来的哈哈哈准备玩两天,第一天先去了白沙湾赶海,但是只抓住了很多寄居蟹和小螃蟹晚上的日落很好看!......
  • 2023.8.4 周五:MySQL相关命令
    1#展示数据库2showdatabases;34#创建数据库5creatdatabase+db1(数据库名称);67#如果创建同样名字的数据库,会报错,可以选择另一条判断语句;8creatdatabaseifnotexistsdb1;910#删除数据库11dropdatabasedb1(数据库名称);1213#如果删......