正题

题目链接:https://www.luogu.com.cn/problem/P7408


题目大意

一个有\(n+1\)层的地牢,从\(i\)到\(i+1\)层要\(A_i\)点能量,第\(i\)层可以花费\(B_i\)获得\(1\)点能量。

\(m\)次询问从\(S_i\)层出发到第\(T_i\)层在能量上限为\(U_i\)的情况下至少需要花费多少。

\(1\leq n,m\leq 2\times 10^5\)


解题思路

模型可以转换成坐标轴上有\(n\)个点,第\(i\)个在\(A_i\),考虑使用一个点获得的能量走的路就是这个点伸出的线覆盖的范围,然后使得范围乘上\(B_i\)的和最小。

考虑能量上限的限制其实就是每个点覆盖的范围不能超过自身的\(U_i\)格。

考虑一个点覆盖范围根据\(U_i\)变化的变化:

  • 没有其他影响,自己正常延伸,此时覆盖范围为一个和\(U_i\)有关的一次函数
  • 延伸到下一个比自己大的位置,不能继续延伸,此时为一个常数
  • 上一个比自己小的数延伸过来,此时为一个单调下降的一次函数
  • 完全被上一个比自己小的覆盖,此时为\(0\)

也就是意味着每个点只需要考虑前后两个比自己小的数分成若干种情况即可。

考虑倒序枚举点,然后用树状数组记录一次项系数的和与二次项系数的和。

对于结尾的限制,我们找到能到达终点的最后的点直接走向它,然后减去那个点的贡献即可。

时间复杂度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#define ll long long
#define lowbit(x) (x&-x)
using namespace std;
const ll N=2e5+10,inf=1e18;
struct node{
ll l,r,u;
}q[N];
ll n,m,a[N],b[N],s[N],ans[N];
ll cnt,u[N],nxt[N],pre[N];
ll f[N][20],g[N][20],lg[N];
vector<ll> d[N],v[N];
stack<ll> st;
ll rmqf(ll l,ll r){
ll z=lg[r-l+1];
l=f[l][z];r=f[r-(1<<z)+1][z];
return (b[l]<b[r])?l:r;
}
ll rmqg(ll l,ll r){
ll z=lg[r-l+1];
l=g[l][z];r=g[r-(1<<z)+1][z];
return (a[l]>a[r])?l:r;
}
struct TreeBinary{
ll t[N];
void Updata(ll x,ll val){
while(x<=cnt){
t[x]+=val;
x+=lowbit(x);
}
return;
}
ll Ask(ll x){
ll ans=0;
while(x){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
void Change(ll l,ll r,ll val){
if(l>r)return;
l=lower_bound(u+1,u+1+cnt,l)-u;
r=upper_bound(u+1,u+1+cnt,r)-u;
Updata(l,val);Updata(r,-val);return;
}
}K,B;
signed main()
{
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++)scanf("%lld",&a[i]),s[i+1]=s[i]+a[i];
for(ll i=1;i<=n;i++)scanf("%lld",&b[i]);
for(ll i=2;i<=n+1;i++)lg[i]=lg[i>>1]+1;
for(ll i=1;i<=n+1;i++)f[i][0]=g[i][0]=i;
for(ll j=1;(1<<j)<=n+1;j++)
for(ll i=1;i+(1<<j)-1<=n+1;i++){
ll x=f[i][j-1],y=f[i+(1<<j-1)][j-1];
f[i][j]=(b[x]<b[y])?x:y;
x=g[i][j-1];y=g[i+(1<<j-1)][j-1];
g[i][j]=(a[x]>a[y])?x:y;
}
for(ll i=n;i>=1;i--){
while(!st.empty()&&b[i]<=b[st.top()])
{pre[st.top()]=i;st.pop();}
if(st.empty())nxt[i]=n+1;
else nxt[i]=st.top();
st.push(i);
}
for(ll i=1;i<=m;i++){
scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].u);u[i]=q[i].u;
ll las=lower_bound(s+1,s+1+n,s[q[i].r]-u[i])-s;
las=min(las,q[i].r-1);las=max(min(las,q[i].r-1),q[i].l);
las=rmqf(las,q[i].r-1);
v[q[i].l].push_back(i);
v[las].push_back(-i);
ans[i]+=(s[q[i].r]-s[las])*b[las];
}
sort(u+1,u+1+m);cnt=unique(u+1,u+1+m)-u-1;
for(ll i=n;i>=1;i--){
K.Change(0,s[nxt[i]]-s[i],b[i]);
B.Change(s[nxt[i]]-s[i]+1,inf,b[i]*(s[nxt[i]]-s[i]));
d[pre[i]].push_back(i);
for(ll j=0;j<d[i].size();j++){
ll x=d[i][j];
K.Change(s[x]-s[i],s[nxt[x]]-s[i],-b[x]);
B.Change(s[x]-s[i],s[nxt[x]]-s[i],b[x]*(s[x]-s[i]));
B.Change(s[nxt[x]]-s[i]+1,inf,-b[x]*(s[nxt[x]]-s[x]));
}
for(ll j=0;j<v[i].size();j++){
ll x=v[i][j],op=1;
if(x<0)x=-x,op=-op;
ll w=lower_bound(u+1,u+1+cnt,q[x].u)-u;
ans[x]+=op*(q[x].u*K.Ask(w)+B.Ask(w));
}
}
for(ll i=1;i<=m;i++){
if(a[rmqg(q[i].l,q[i].r-1)]>q[i].u)puts("-1");
else printf("%lld\n",ans[i]);
}
return 0;
}

P7408-[JOI 2021 Final]ダンジョン 3【贪心,树状数组】的更多相关文章

  1. Luogu P5103 「JOI 2016 Final」断层 树状数组or线段树+脑子

    太神仙了这题... 原来的地面上升,可以倒着操作(时光倒流),转化为地面沉降,最后的答案就是每个点的深度. 下面的1,2操作均定义为向下沉降(与原题意的变换相反): 首先这个题目只会操作前缀和后缀,并 ...

  2. 【bzoj4240】有趣的家庭菜园 贪心+树状数组

    题目描述 对家庭菜园有兴趣的JOI君每年在自家的田地中种植一种叫做IOI草的植物.JOI君的田地沿东西方向被划分为N个区域,由西到东标号为1~N.IOI草一共有N株,每个区域种植着一株.在第i个区域种 ...

  3. 贪心+树状数组维护一下 Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) D

    http://codeforces.com/contest/724/problem/D 题目大意:给你一个串,从串中挑选字符,挑选是有条件的,按照这个条件所挑选出来的字符集合sort一定是最后选择当中 ...

  4. D 洛谷 P3602 Koishi Loves Segments [贪心 树状数组+堆]

    题目描述 Koishi喜欢线段. 她的条线段都能表示成数轴上的某个闭区间.Koishi喜欢在把所有线段都放在数轴上,然后数出某些点被多少线段覆盖了. Flandre看她和线段玩得很起开心,就抛给她一个 ...

  5. [BZOJ4240]有趣的家庭菜园(贪心+树状数组)

    最后数列一定是单峰的,问题就是最小化最后的位置序列的逆序对数. 从大到小加数,每次贪心看放左边和右边哪个产生的逆序对数更少,树状数组即可. 由于大数放哪对小数不产生影响,所以正确性显然. 注意相同数之 ...

  6. [P4064][JXOI2017]加法(贪心+树状数组+堆)

    题目描述 可怜有一个长度为 n 的正整数序列 A,但是她觉得 A 中的数字太小了,这让她很不开心. 于是她选择了 m 个区间 [li, ri] 和两个正整数 a, k.她打算从这 m 个区间里选出恰好 ...

  7. [luoguP2672] 推销员(贪心 + 树状数组 + 优先队列)

    传送门 贪心...蒟蒻证明不会... 每一次找最大的即可,找出一次最大的,数列会分为左右两边,左边用stl优先队列维护,右边用树状数组维护.. (线段树超时了....) 代码 #include < ...

  8. codeforces 1249 D2 Too Many Segments (hard version) 贪心+树状数组

    题意 给定n个线段,线段可以相交,第\(i\)个线段覆盖的区间为\([l_i,r_i]\),问最少删除多少个线段让覆盖每个点的线段数量小于等于k. 分析 从左往右扫每个点\(x\),若覆盖点\(x\) ...

  9. [JZO6401]:Time(贪心+树状数组)

    题目描述 小$A$现在有一个长度为$n$的序列$\{x_i\}$,但是小$A$认为这个序列不够优美. 小$A$认为一个序列是优美的,当且仅当存在$k\in [1,n]$,满足:$$x_1\leqsla ...

随机推荐

  1. java导出excel(easypoi)

    介绍 easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 ...

  2. Anaconda Pycharm 是怎么个事儿?

    前言 许多人学习Python的经历可能很相似,写程序没有问题,最后却被各种环境困扰. 不论你是Python小白,还是学习Python有一段时间了.都可以认真的看一下ヾ(≧▽≦*)o 这篇文章让你对An ...

  3. Flink中的算子操作

    一.Connect DataStream,DataStream ->  ConnectedStream,连接两个保持他们类型的数据流,两个数据流被Connect之后,只是被放在了同一个流中,内部 ...

  4. [转]VRRP协议详解

    原文地址:VRRP协议详解 文中涉及缩略语 缩略语 英文全名 中文解释 VRRP Virtual Router Redundancy Protocol 虚拟路由器冗余协议 NQA Network Qu ...

  5. go协程调度

    目录 前言 1. 线程池的缺陷 2.Goroutine 调度器 3.调度策略 3.1 队列轮转 3.2 系统调用 3.3 工作量窃取 4.GOMAXPROCS设置对性能的影响 参考 前言 Gorout ...

  6. jdbc操作mysql(四):利用反射封装

    前言 有了前面利用注解拼接sql语句,下面来看一下利用反射获取类的属性和方法 不过好像有一个问题,数据库中的表名和字段中带有下划线该如何解决呢 实践操作 工具类:获取connection对象 publ ...

  7. 超详细kafka教程来啦

    Kafka的概念和入门 Kafka是一个消息系统.由LinkedIn于2011年设计开发. Kafka是一种分布式的,基于发布/订阅的消息系统.主要设计目标如下: 以时间复杂度O(1)的方式提供消息持 ...

  8. IOS 集成 Bilibili IJKPlayer播放器,播放rtmp视频流

    因为公司项目需要,我一个连iPhone都没用过的人竟然跑去开发iOS APP.近一段时间一直忙于赶项目,到今天差不多了,所以记录一下当时遇到的各种坑,先从ios 集成 ijkplayer播放器说起! ...

  9. windows 安装pip 及更换pip国内源

    一.官网下载压缩包并解压. 官网:https://pypi.org/project/pip/#files 文件:选择.tar.gz版本 image 解压后,进入解压文件目录,在当前路径下打开cmd窗口 ...

  10. 数据治理中Oracle SQL和存储过程的数据血缘分析

    数据治理中Oracle SQL和存储过程的数据血缘分析   数据治理中的一个重要基础工作是分析组织中数据的血缘关系.有了完整的数据血缘关系,我们可以用它进行数据溯源.表和字段变更的影响分析.数据合规性 ...