当前位置: 首页 > news >正文

【ST表、倍增】P7167 [eJOI 2020] Fountain (Day1)

题目描述

大家都知道喷泉吧?现在有一个喷泉由 NNN 个圆盘组成,从上到下以此编号为 1∼N1 \sim N1N,第 iii 个喷泉的直径为 DiD_iDi,容量为 CiC_iCi,当一个圆盘里的水大于了这个圆盘的容量,那么水就会溢出往下流,直到流入半径大于这个圆盘的圆盘里。如果下面没有满足要求的圆盘,水就会流到喷泉下的水池里。

现在给定 QQQ 组询问,每一组询问这么描述:

  • 向第 RiR_iRi 个圆盘里倒入 ViV_iVi 的水,求水最后会流到哪一个圆盘停止。

如果最终流入了水池里,那么输出 000

注意,每个询问互不影响。

输入格式

第一行两个整数 N,QN,QN,Q 代表圆盘数和询问数。
接下来 NNN 行每行两个整数 Di,CiD_i,C_iDi,Ci 代表一个圆盘。
接下来 QQQ 行每行两个整数 Ri,ViR_i,V_iRi,Vi 代表一个询问。

输出格式

QQQ 行每行一个整数代表询问的答案。

对于 100%100\%100% 的数据:

  • 2≤N≤1052 \le N \le 10^52N105
  • 1≤Q≤2×1051 \le Q \le 2 \times 10^51Q2×105
  • 1≤Ci≤10001 \le C_i \le 10001Ci1000
  • 1≤Di,Vi≤1091 \le D_i,V_i \le 10^91Di,Vi109
  • $ 1\le R_i \le N$。

思路

可以将水池看作第 n+1n + 1n+1 个圆盘,直径和容量都是无穷大。

考虑将题目划分成2部分:如何求直径大于自己的下一个圆盘,如何求出一共需要经过几次下一个圆盘才能把水装满。

对于第一部分,可以先用 ST 表求出区间最大值。不妨设当前圆盘是第 iii 个,容易发现一定存在一个最小的 jjj 使 max⁡k=i+1jDk>Di\max^{j}_{k = i+1}D_k > D_imaxk=i+1jDk>Di,且当 P>jP>jP>j 时都有 max⁡k=i+1PDk≥max⁡k=i+1jDk>Di\max^{P}_{k = i+1}D_k \geq \max^{j}_{k = i+1}D_k> D_imaxk=i+1PDkmaxk=i+1jDk>Di 成立,因此满足单调性,可以用二分来求出这个 jjj。ST 表预处理 O(NlogN)O(NlogN)O(NlogN),单次查询 O(1)O(1)O(1)。对于 nnn 个圆盘二分,复杂度也是 O(NlogN)O(NlogN)O(NlogN),总复杂度 O(NlogN)O(NlogN)O(NlogN)

对于第二部分。如果对于每次查询都一个一个往下一个圆盘跳,则当圆盘大小单调递增的时候,总复杂度可能达到 O(nQ)O(nQ)O(nQ),无法接受。考虑用倍增的方法,一次往下跳 2k2^k2k 个,kkk 同理也可以二分求出,总复杂度还是 O(QlogN)O(QlogN)O(QlogN),常数稍微大一点。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,q,nex[100005][25],add[100005][25],maxx[100005][25];
int d[100005],c[100005];
//l 到 r 之间区间最大直径 
int ask_max(int l,int r) {int t = 0;for(;(1 << t) <= (r - l + 1);) {t++;}t--; return max(maxx[l][t],maxx[r - (1 << t) + 1][t]);
}
signed main() {scanf("%lld %lld",&n,&q);for(int i = 1;i <= n;i++) {scanf("%lld %lld",&d[i],&c[i]);maxx[i][0] = d[i]; }d[n + 1] = 1000000000005,c[n + 1] = 10000000000005;for(int i = 1;(1 << i) <= n + 1;i++) {for(int j = 1;j + (1 << i) - 1 <= n + 1;j++) {maxx[j][i] = max(maxx[j][i - 1],maxx[j + (1 << (i - 1))][i - 1]);}}for(int i = 1;i <= n;i++) {int l = i + 1,r = n + 1,mid;while(l < r) {mid = (l + r) >> 1;if(ask_max(i + 1,mid) > d[i]) r = mid;else l = mid + 1;}nex[i][0] = i,add[i][0] = c[i];nex[i][1] = l,add[i][1] = c[l] + c[i];}for(int i = 0;i <= 24;i++) nex[n + 1][i] = n + 1,add[n + 1][i] = c[n + 1];for(int i = 2;i <= 20;i++) {for(int j = 1;j <= n;j++) {nex[j][i] = nex[nex[nex[j][i - 1]][1]][i - 1];add[j][i] = add[j][i - 1] + add[nex[nex[j][i - 1]][1]][i - 1];}}while(q--) {int now,v;scanf("%lld %lld",&now,&v);while(v) {if(v <= c[now]) {if(now != n + 1) printf("%lld\n",now);else printf("0\n");break;}int l = 0,r = 20,mid;while(l < r - 1) {mid = (l + r) >> 1;if(add[now][mid] >= v) r = mid - 1;else l = mid; }		v -= add[now][l];now = nex[nex[now][l]][1];} }return 0;
}
http://www.dtcms.com/a/301406.html

相关文章:

  • QT6 源,七章对话框与多窗体(15)多文档 MDI 窗体 QMdiArea 篇一:属性,公共成员函数,信号与槽函数
  • 多智能体架构
  • 《计算机组成原理与汇编语言程序设计》实验报告四 Debug及指令测试
  • setnonblocking函数用途和使用案例
  • 在本地环境中运行 ‘dom-distiller‘ GitHub 库的完整指南
  • OSPF路由协议 多区域
  • 【ESP32】无法找到: “${env:IDF_PATH}/components/“的路径报错问题以及CMAKE构建不成功问题
  • Cursor报错解决【持续更新中】
  • 金融科技中的远程开户、海外个人客户在线开户、企业客户远程开户
  • 深入解析Java运行机制与JVM内存模型
  • 【Web APIs】JavaScript 节点操作 ⑩ ( 节点操作综合案例 - 动态生成表格案例 )
  • windows 11 JDK11安装
  • LeetCode 239:滑动窗口最大值
  • 五自由度磁悬浮轴承转子不平衡振动抑制破局:不平衡前馈补偿+自抗扰控制实战解析
  • MySQL 全详解:从入门到精通的实战指南
  • 第二阶段-第二章—8天Python从入门到精通【itheima】-138节(MySQL的综合案例)
  • 设备分配与回收
  • 数据处理实战(含代码)
  • OpenFeign-远程调用((Feign的使用方法))
  • Spring Boot 配置文件常用配置属性详解(application.properties / application.yml)
  • 【PCIe 总线及设备入门学习专栏 5.3.4 -- PCIe PHY Firmware 固件加载流程】
  • 如何思考一个动态规划问题需要几个状态?
  • [每周一更]-(第150期):AI Agents:从概念到实践的智能体时代
  • net8.0一键创建支持(Elastic)
  • 2025C卷 - 华为OD机试七日集训第1期 - 按算法分类,由易到难,循序渐进,玩转OD
  • Spring 容器注入时查找 Bean 的完整规则
  • Flutter中 Provider 的基础用法超详细讲解(二)之ChangeNotifierProvider
  • 力扣热题100----------53最大子数组和
  • 咨询进阶——解读40页公司战略解码方法【附全文阅读】
  • sed命令