首页 > 其他分享 >P3081 [USACO13MAR] Hill Walk G

P3081 [USACO13MAR] Hill Walk G

时间:2024-01-23 13:55:38浏览次数:31  
标签:x1 return int 线段 P3081 Walk _. Hill now

原题面:Luogu

知识点:扫描线,李超树。

被离散化鲨了哈哈,一个人交了三页半,感谢大神的提交记录救我一命呜呜:https://www.luogu.com.cn/record/123948215

简述

给定平面坐标系上的 \(n\) 条线段,每条线段的两个端点为 \((x_1, y_1)\),\((x_2, y_2)\) 且满足 \(x_1<x_2\),\(y_1<y_2\),且有且仅有第一条线段满足 \((x_1, y_1) = (0,0)\)。
每条线段都代表一座山。初始时一个人位于 \((0, 0)\) 并在第一座山开始向右攀登,最右端 \((x_2, y_2)\) 是山的边缘,他会在边缘进行一个信仰之跃向下跳到横坐标为 \(x_2\) 位置并尝试降落到其他山上的非边缘位置,若降落到另一座山上则会继续在新的山上进行攀登,否则就摔似了(悲
求这个人似之前攀登过了多少座山。
\(1\le n\le 10^5\),\(0\le x_1<x_2\le 10^9\),\(0\le y_1<y_2\le 10^9\)。
1S,125MB。

分析

初始时位于第一条线段上,考虑模拟攀登的过程,在边缘向下跳到最高的山上等价于找与 \(x = x_2\) 交点纵坐标最大的线段,考虑使用李超树加入寻找后继的过程。但是要保证要找的线段可以降落到达,而李超树不支持删除操作,不能在一开始就将所有线段插入并仅在要查询降落到的下一座山时将不能到达的删除,则考虑使用扫描线在查询时先仅将对此时有贡献的插入。

设当前位于的线段为 \((x_1, y_1)\rightarrow (x_2, y_2)\),则可能成为当前线段后继的线段 \((x_1', y_1')\rightarrow (x_2', y_2')\) 一定满足 \(x_1'\le x_1\),\(x_2'>x_2\) 且在 \(x=x_2\) 处交点坐标不大于 \(y_2\)。如果先将所有线段按左端点 \(x_1'\) 进行排序然后依次枚举,则这些线段一定是连续的一段区间,考虑按照上述限制枚举这段区间并将每条线段插入到李超树区间 \([x_1', x_2'-1]\) 中,查询 \(x=x_2\) 处即可得到后继,经过的山数量加一,若不存在则停止。

横坐标范围比较大注意先离散化再插入到李超树中。但需要注意如果仅把所有线段的横坐标离散化并直接替换原线段,可能会导致新的线段间出现相交的情况,因为只离散化横坐标后计算线段的斜率,相当于直接把一段很长的区间缩没了,这么搞显然不行。我的解决方案是仅在将线段插入李超树使用离散化后的横坐标表示区间,在计算线段某点的值时仍使用原始的横坐标

总时间复杂度 \(O(n\log^2 n)\) 级别。

代码

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
#define pr std::pair
#define mp std::make_pair
const int kN = 1e5 + 10;
const int kX = kN << 2;
const double eps = 1e-9;
const double kInf = 1e18 + 2077;
//=============================================================
struct Line {
  LL x1, y1, x2, y2;
  int l, r, p;
  double k, b;
} l[kN];
int n, linenum;
int datanum, data[kN << 2];
int now, nowp, nowh, ans;
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0'); 
  return f * w;
}
int cmp(double x_, double y_) {
  if (x_ - y_ > eps) return 1;
  if (y_ - x_ > eps) return -1;
  return 0;
}
double calc(int id_, int x_) {
  double ret = l[id_].b + l[id_].k * x_;
  return ret;
}
void Add(int x0_, int y0_, int x1_, int y1_) {
  ++ linenum;
  if (x0_ == x1_) {
    l[linenum].k = 0;
    l[linenum].b = 1.0 * std::min(y0_, y1_);
  } else{
    l[linenum].k = 1.0 * (y1_ - y0_) / (x1_ - x0_);
    l[linenum].b = y0_ - l[linenum].k * x0_;
  }
}
bool cmp1(Line fir_, Line sec_) {
  if (fir_.x1 != sec_.x1) return fir_.x1 < sec_.x1;
  return fir_.y2 > sec_.y2;
}
namespace LSeg {
  #define ls (now_<<1)
  #define rs (now_<<1|1)
  #define mid ((L_+R_)>>1)
  const int kNode = kX << 3;
  int t[kNode];
  void Update(int now_, int L_, int R_, int u_) {
    int& v_ = t[now_];
    int bmid = cmp(calc(u_, data[mid]), calc(v_, data[mid]));
    if (bmid == 1 || (!bmid && u_ < v_)) std::swap(u_, v_);
    int bl = cmp(calc(u_, data[L_]), calc(v_, data[L_]));
    int br = cmp(calc(u_, data[R_]), calc(v_, data[R_]));
    if (bl == 1 || (!bl && u_ < v_)) Update(ls, L_, mid, u_);
    if (br == 1 || (!br && u_ < v_)) Update(rs, mid + 1, R_, u_);
  }
  void Modify(int now_, int L_, int R_, int l_, int r_, int u_) {
    if (l_ <= L_ && R_ <= r_) {
      Update(now_, L_, R_, u_);
      return ;
    }
    if (l_ <= mid) Modify(ls, L_, mid, l_, r_, u_);
    if (r_ > mid) Modify(rs, mid + 1, R_, l_, r_, u_);
  }
  pr <double, int> pmax(pr <double, int> x_, pr <double, int> y_) {
    if (cmp(x_.first, y_.first) == -1) return y_;
    if (cmp(x_.first, y_.first) == 1) return x_; 
    return x_.second < y_.second ? x_ : y_;
  }
  pr <double, int> Query(int now_, int L_, int R_, int pos_) {
    if (R_ < pos_ || pos_ < L_) return {-kInf, 0};
    double val_ = calc(t[now_], data[pos_]);
    if (L_ == R_) return mp(val_, t[now_]);
    return pmax(mp(val_, t[now_]), pmax(Query(ls, L_, mid, pos_), 
                                        Query(rs, mid + 1, R_, pos_)));
  }
  #undef ls
  #undef rs
  #undef mid
}
void Init() {
  n = read();
  for (int i = 1; i <= n; ++ i) {
    l[i].x1 = read(), l[i].y1 = read();
    l[i].x2 = read(), l[i].y2 = read();
    l[i].l = l[i].x1, l[i].p = l[i].x2, l[i].r = l[i].x2 - 1;
    data[i] = l[i].x1, data[i + n] = l[i].x2;
    data[i + 2 * n] = l[i].r;
  }
  std::sort(data + 1, data + 3 * n + 1);
  datanum = std::unique(data + 1, data + 3 * n + 1) - data - 1;
  for (int i = 1; i <= n; ++ i) {
    l[i].l = std::lower_bound(data + 1, data + datanum + 1, l[i].l) - data;
    l[i].r = std::lower_bound(data + 1, data + datanum + 1, l[i].r) - data;
    l[i].p = std::lower_bound(data + 1, data + datanum + 1, l[i].p) - data;
  }
  std::sort(l + 2, l + n + 1, cmp1);
  for (int i = 1; i <= n; ++ i) {
    Add(l[i].x1, l[i].y1, l[i].x2, l[i].y2);
  }

  l[0].b = -kInf;
}
//=============================================================
int main() {
  // freopen("3.txt", "r", stdin);
  // freopen("2.txt", "r", stdin);
  Init();
  ans = 1;
  now = 1, nowp = l[1].x2, nowh = l[1].y2;
  
  for (int i = 2; ; ) {
    for (; i <= n; ++ i) {
      if (l[i].x1 > nowp) break;
      if (l[i].x2 <= nowp || calc(i, nowp) > nowh) continue;
      LSeg::Modify(1, 1, datanum, l[i].l, l[i].r, i);
    }
    int ret = LSeg::Query(1, 1, datanum, l[now].p).second;
    if (!ret) break;
    ++ ans;
    now = ret, nowp = l[now].x2, nowh = l[now].y2;
  }
  printf("%d\n", ans);
  return 0;
}

标签:x1,return,int,线段,P3081,Walk,_.,Hill,now
From: https://www.cnblogs.com/luckyblock/p/17982298

相关文章

  • Star Walk和Solar Walk
    StarWalk和SolarWalk是两款由VitoTechnology开发的天文应用程序,它们都提供了关于天体和宇宙的信息,但在功能和重点上有所不同。StarWalk是一款天文学教育应用程序,主要关注天空观测和天体识别。它提供了一个实时的星空地图,可以显示当前的天体位置、星座、行星、卫星、彗星等。......
  • 【Centos】Centos 7.6 Skywalking 9.2.0,自监控
    1  前言今儿试试 Skywalking自监控。2 安装步骤2.1 下载open-telemetry地址:https://hub.nuaa.cf/open-telemetry/opentelemetry-collector-releases/releases/,我下载的是0.89.0版本的哈:2.2 安装open-telemetryrpm-ivhotelcol_0.89.0_linux_amd64.rpm2.......
  • SkyWalking服务监控简单配置【Windows版本】
    SkyWalking是什么skywalking是一个可观测性分析平台和应用性能管理系统专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。下载官网:https://skywalking.apache.org/下载地址:https://skywalking.apache.org/downloads/中文文档:https://skyapm.github.io/doc......
  • Skywalking(8.7)安装以及docker镜像打包
    Skywalking安装以及docker镜像打包Skywalking版本:apache-skywalking-apm-es7-8.7.0ES版本:7.17.2一.下载Skywalking的安装包下载地址:Indexof/dist/skywalking/8.7.0(apache.org)上传到服务器安装目录并解压#这里选择的安装目录是/usr/localcd/usr/localtar-zxvf......
  • 在Python中,如果你想查找特定的SQLite数据库文件(例如'mydatabase.db'),你可以使用os模块
    这是Python中os.walk()函数的常见用法¹²⁴⁵⁶。os.walk()函数用于递归遍历指定目录及其子目录,并返回一个生成器,每次迭代都会返回一个包含三个元素的元组:当前目录的路径、当前目录下所有子目录的列表和当前目录下所有文件的列表¹²⁴⁵⁶。在fordirpath,dirnames,filenamesi......
  • day22 Skywalking的整体架构及特性-基于Helm的Skywalking部署管理 (8.1-8.2)
    8.1-Skywalking的整体架构及特性一、为什么需要链路追踪随着云计算和微服务架构的普及,越来越多的企业开始采用分布式架构开放应用程序。在这种复杂的架构中,应用程序的性能问题变得更加棘手,传统的单机监测工具已经无法满足需求。二、Skywalking简介Skywalking是国内开源的基......
  • Spring Boot2.x 集成 Skywalking 9.1.0
    参考https://skywalking.apache.org/https://www.cnblogs.com/xiaqiuchu/p/17931230.html(本文使用的该文章的代码,进入可下载源码)https://juejin.cn/post/7001849172278116389#heading-7注意事项本文代码环境为单注册中心、单服务提供者、单消费者。管理面板左侧菜单在没......
  • windchill 解决80端口被占用问题
    访问测试机是发现:80端口被占用了。发现80端口被ntoskrnl.exe占用具体解除端口占用办法,参考此文章https://blog.csdn.net/weixin_45866737/article/details/122594326修改apache,参考此处......
  • skywalking对接python
    1.官网:https://skywalking.apache.org/docs/skywalking-python/next/readme/2.安装pipinstall"apache-skywalking"3.集成到flask,启动服务fromflaskimportFlask,request,render_templatefromupload_file_to_s3importuploads3,get_md5fromskywalkingimp......
  • skywalking--Prometheus Fetcher使用
    1.准备:实验版本:skywalking9.1.0官网:https://skywalking.apache.org/docs/main/v9.1.0/en/setup/backend/prometheus-metrics/ 2.开启prometheus遥测数据修改skywalking配置,修改${SW_TELEMETRY:prometheus}telemetry:selector:${SW_TELEMETRY:prometheus}none:......