P7408-[JOI 2021 Final]ダンジョン 3【贪心,树状数组】
正题
题目链接: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【贪心,树状数组】的更多相关文章
- Luogu P5103 「JOI 2016 Final」断层 树状数组or线段树+脑子
太神仙了这题... 原来的地面上升,可以倒着操作(时光倒流),转化为地面沉降,最后的答案就是每个点的深度. 下面的1,2操作均定义为向下沉降(与原题意的变换相反): 首先这个题目只会操作前缀和后缀,并 ...
- 【bzoj4240】有趣的家庭菜园 贪心+树状数组
题目描述 对家庭菜园有兴趣的JOI君每年在自家的田地中种植一种叫做IOI草的植物.JOI君的田地沿东西方向被划分为N个区域,由西到东标号为1~N.IOI草一共有N株,每个区域种植着一株.在第i个区域种 ...
- 贪心+树状数组维护一下 Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) D
http://codeforces.com/contest/724/problem/D 题目大意:给你一个串,从串中挑选字符,挑选是有条件的,按照这个条件所挑选出来的字符集合sort一定是最后选择当中 ...
- D 洛谷 P3602 Koishi Loves Segments [贪心 树状数组+堆]
题目描述 Koishi喜欢线段. 她的条线段都能表示成数轴上的某个闭区间.Koishi喜欢在把所有线段都放在数轴上,然后数出某些点被多少线段覆盖了. Flandre看她和线段玩得很起开心,就抛给她一个 ...
- [BZOJ4240]有趣的家庭菜园(贪心+树状数组)
最后数列一定是单峰的,问题就是最小化最后的位置序列的逆序对数. 从大到小加数,每次贪心看放左边和右边哪个产生的逆序对数更少,树状数组即可. 由于大数放哪对小数不产生影响,所以正确性显然. 注意相同数之 ...
- [P4064][JXOI2017]加法(贪心+树状数组+堆)
题目描述 可怜有一个长度为 n 的正整数序列 A,但是她觉得 A 中的数字太小了,这让她很不开心. 于是她选择了 m 个区间 [li, ri] 和两个正整数 a, k.她打算从这 m 个区间里选出恰好 ...
- [luoguP2672] 推销员(贪心 + 树状数组 + 优先队列)
传送门 贪心...蒟蒻证明不会... 每一次找最大的即可,找出一次最大的,数列会分为左右两边,左边用stl优先队列维护,右边用树状数组维护.. (线段树超时了....) 代码 #include < ...
- codeforces 1249 D2 Too Many Segments (hard version) 贪心+树状数组
题意 给定n个线段,线段可以相交,第\(i\)个线段覆盖的区间为\([l_i,r_i]\),问最少删除多少个线段让覆盖每个点的线段数量小于等于k. 分析 从左往右扫每个点\(x\),若覆盖点\(x\) ...
- [JZO6401]:Time(贪心+树状数组)
题目描述 小$A$现在有一个长度为$n$的序列$\{x_i\}$,但是小$A$认为这个序列不够优美. 小$A$认为一个序列是优美的,当且仅当存在$k\in [1,n]$,满足:$$x_1\leqsla ...
随机推荐
- vs code 调试angular2
调试步骤: 1.安装nodejs 2.安装vscode 3.vscode安装debugger for chrome插件 4.选择调试->打开调试配置,选择chrome配置,打开lauch.jso ...
- redis和memecache有什么区别?
1.memcache所有值均是简单地字符串,redis有复杂的数据类型. 2.memcache不支持数据持久化,redis支持数据持久化. 3.redis速度比memcache快,redis构建了自己 ...
- join控制线程的执行循序 T1 -> T2 -> T3
/** * 控制线程的执行循序 T1 -> T2 -> T3 * join实现 */ public static void join(){ Thread t1 = new Thread(( ...
- MongoDB 数据库创建删除、表(集合) 创建删除、数据增删改查
使用数据库.创建数据库 use student 如果真的想把这个数据库创建成功,那么必须插入一个数据. 数据库中不能直接插入数据,只能往集合(collections)中插入数据.不需要专门创建集合,只 ...
- vue--三种组件中之间的传值
参考网址:https://www.jianshu.com/p/46573a741c29 一.父子组件之间的传值----props/$emit 组件之间的传值,我们比较常用到的是props/$emit ...
- QT 编译的过程
- 深入浅出Mybatis系列(六)---配置详解之typeAliases别名
本篇继续讲剩下的配置节点之一:typeAliases. typeAliases节点主要用来设置别名,其实这是挺好用的一个功能, 通过配置别名,我们不用再指定完整的包名,并且还能取别名. 例如: 我们在 ...
- servlet中servletContext的五大作用(二)
1. 获取web的上下文路径 2. 获取全局的参数 3. 作为域对象使用 4. 请求转发 5. 读取web项目的资源文件 package day10.about_serv ...
- playwright-python 元素定位、frame处理(一)
浏览器.Browser contexts.frame Playwright 可以同时启动多个浏览器(chromium.Firefox.webkit),每个浏览器可以启动多个page(在Playwrig ...
- ubantu上面 NFS服务器安装
---恢复内容开始--- N月一更............ 本博客部分参照:https://blog.csdn.net/CSDN_duomaomao/article/details/77822883 ...