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 ...
随机推荐
- WindowsService开发简单入门
参考网址: https://www.cnblogs.com/wenlong512/p/7355971.html 一.简介 程序创建在 Windows 会话中,可长时间运行的可执行应用程序.这些服务可以 ...
- C#用SOCKET发送HTTP请求小例
private void button1_Click(object sender, EventArgs e) { string urlStr = this.textUrl.Text ; if (url ...
- Redis5.0 配置文件中文参考
Redis 5.0 配置文件#是否在后台执行,yes:后台运行:no:不是后台运行daemonize yes#是否开启保护模式,默认开启.要是配置里没有指定bind和密码.开启该参数后,redis只会 ...
- 关于腾讯云redis 无法外网访问的解决方案
问题简介: 今天购买了一台腾讯云的redis:如图 可是我没有找到 腾讯云提供的外网地址,我该怎么连接呢?百度了一大堆 全部是 在腾讯云服务器上搭建的Redis实例的解决办法.完全不匹配. 开始解决: ...
- C++ 各种构造函数
c++构造函数的知识在各种c++教材上已有介绍,不过初学者往往不太注意观察和总结其中各种构造函数的特点和用法,故在此我根据自己的c++编程经验总结了一下c++中各种构造函数的特点,并附上例子,希望对初 ...
- SpringCloud之网关zuul
1.微服务网关介绍和使用场景 1)什么是网关 API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求.鉴权.监控.缓存.限流等功能 统一接入 智 ...
- java发送短信开发,第三方接口方法
必备的三个jar包Maven有自己去下: commons-logging commons-logging 1.1 commons-httpclient commons-httpclient 3.1 c ...
- ASP截取字符 截取字符之间的字符
ASP截取字符:MID函数Mid(变量或字串符,开始字节, 结尾字节(可不填)) InStrRev(变量, "字串符") 最后出现位置InStr(变量, "字串符&qu ...
- 3k+2形式的素数相关的两个命题的证明
- mysql8.0----mysqldump抛出:Unknown table 'COLUMN_STATISTICS' in information_schema (1109)
问题:我尝试使用mysqldump时,得到以下错误: 复制 $> mysqldump --single-transaction --h -u user -p db > db.sql my ...