正题

题目链接: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. sql查询第10条到第20条数据

    select top(10) * from T1 where Id >= (select MAX(Id) from (select top(20) * from T1 order by Id) ...

  2. C#多线程---I/O线程实现异步请求

    一.场景 利用I/O线程来模拟浏览器对服务器请求的异步操作. 二.例子 1 using System; 2 using System.Collections.Generic; 3 using Syst ...

  3. TNN iOS非图像模型入门

    注:本文同步发布于微信公众号:stringwu的互联网杂谈TNN iOS 非图像模型入门指南 1 背景 TNN是腾讯优图实验室开源的高性能.轻量级神经网络推理框架TNN,github上也有比较详细的例 ...

  4. 【C语言】第2章 算法 — 程序的灵魂

    第2章 算法 - 程序的灵魂 一个程序主要包括以下两方面的信息: 对数据的描述.在程序中要指定用到哪些数据以及这些数据的类型和数据的组织形式 也就是数据结构(data structure) 对操作的描 ...

  5. 记一次 .NET 某机械臂智能机器人控制系统MRS CPU爆高分析

    一:背景 1. 讲故事 这是6月中旬一位朋友加wx求助dump的故事,他的程序 cpu爆高UI卡死,问如何解决,截图如下: 在拿到这个dump后,我发现这是一个关于机械臂的MRS程序,哈哈,在机械臂这 ...

  6. go语言学习代码

    1.day01 package main //声明文件所在的包,每个go文件必须有归属包 import "fmt" //引入程序中需要用的包,为了使用包下的函数 比如函数:Prin ...

  7. docker一分钟搭建nginx服务器

    运行nginx服务 拉取: docker pull nginx:1.17.9 运行: docker run -d --name nginx -P 80:80 nginx:1.17.9 -d表示在后台启 ...

  8. 什么是内存屏障? Why Memory Barriers ?

           要了解如何使用memory barrier,最好的方法是明白它为什么存在.CPU硬件设计为了提高指令的执行速度,增设了两个缓冲区(store buffer, invalidate que ...

  9. AQS快速入门

    一.模板方法模式 父子类多态,父类中用一个方法调用执行所有所需要的方法: 父类: 子类: 主线程执行时候调用父类的模板方法: 二.AQS思想 sync都是独占锁,lock显示锁也是,只有读写锁是共享锁 ...

  10. vue.js框架图片上传组件

    html: <div id="app"> <div class="hello"> <div class="upload& ...