https://www.luogu.org/problemnew/show/P5044

题解

这种关于最大值或者最小值的问题,可以往笛卡尔树的方面想。

先考虑一个朴素的\(dp\),设\(dp[l][r]\)表示\(l\sim r\)的答案,转移是:

\[dp[l][r]=min(dp[l][p-1]+a[p]*(r-p+1),dp[p+1][r]+a[p]*(p-l+1))
\]

\[p=min(a[l]\sim a[r])
\]

这个东西乍一看好像没什么优化空间,但是由于我们有笛卡尔树,所以我们可以加一些限制。

比如说我们强制让询问区间的一个端点为笛卡尔树上的某个端点。

然后考虑这时的转移:

\[dp[l][i]=min(dp[l][p-1]+a[p]*(i-p+1),dp[p+1][i]+(p-l+1)*a[p])
\]

我们观察到随着\(i\)的向右移动,前面的部分每次都会增加\(a[p]\),后面的的部分每次增加都不会超过\(a[p]\)(根据笛卡尔树的性质)。

于是我们可以发现准备更新的这段区间被分为两部分,一部分是区间加等差数列,一部分是加常数,这个可以用线段树上二分完成。

对于一般的区间,我们直接可以把它拆成两种情况:选在最大值左边或者选在最大值右边,这样端点就有保障了,最后我们把两种情况的答案取个\(min\)就可以了。

Warning

打标记的时候要注意,因为下放的时候标记会清空,所以区间的值直接累加,不要直接更新。

代码

#include<bits/stdc++.h>
#define ls cnt<<1
#define rs cnt<<1|1
#define N 750009
using namespace std;
typedef long long ll;
ll h[N],ans[N],ans1[N],ans2[N];
int n,lo[N],p[23][N],ch[N][2],Q,rot;
vector<int>vec1[N],id1[N],vec2[N],id2[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline int _max(int a,int b){return h[a]<h[b]?b:a;}
inline int f(int x){return n-x+1;}
inline int RMQ(int l,int r){
int loo=lo[r-l+1];
return _max(p[loo][l],p[loo][r-(1<<loo)+1]);
}
struct node{
ll val1,val2,k,b;
int tag;
}tr[N<<2];
inline void cover(int cnt,int l,int r,ll k,ll b){
tr[cnt].k=k;tr[cnt].b=b;
tr[cnt].val1=k*l+b;tr[cnt].val2=k*r+b;
tr[cnt].tag=1;
}
inline void add(int cnt,int l,int r,ll k,ll b){
tr[cnt].k+=k;tr[cnt].b+=b;
tr[cnt].val1+=k*l+b;
tr[cnt].val2+=k*r+b;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if(!tr[cnt].tag)tr[cnt].tag=2;
}
inline void pushdown(int cnt,int l,int r){
int mid=(l+r)>>1;
if(tr[cnt].tag){
if(tr[cnt].tag==1)cover(ls,l,mid,tr[cnt].k,tr[cnt].b),cover(rs,mid+1,r,tr[cnt].k,tr[cnt].b);
else add(ls,l,mid,tr[cnt].k,tr[cnt].b),add(rs,mid+1,r,tr[cnt].k,tr[cnt].b);
tr[cnt].k=tr[cnt].b=tr[cnt].tag=0;
}
}
inline void build(int &cnt,int l,int r){
if(l>r){cnt=0;return;}
cnt=RMQ(l,r);
build(ch[cnt][0],l,cnt-1);
build(ch[cnt][1],cnt+1,r);
}
ll query(int cnt,int l,int r,int x){
if(l==r)return tr[cnt].val1;
int mid=(l+r)>>1;
pushdown(cnt,l,r);
if(mid>=x)return query(ls,l,mid,x);
else return query(rs,mid+1,r,x);
}
void clear(int cnt,int l,int r){
tr[cnt].k=tr[cnt].val1=tr[cnt].val2=tr[cnt].b=tr[cnt].tag=0;
if(l==r)return;
int mid=(l+r)>>1;
clear(ls,l,mid);clear(rs,mid+1,r);
}
void upd(int cnt,int l,int r,int x,ll y){
if(l==r){
add(cnt,l,r,0,y);
return;
}
pushdown(cnt,l,r);
int mid=(l+r)>>1;
if(mid>=x)upd(ls,l,mid,x,y);
else upd(rs,mid+1,r,x,y);
tr[cnt].val1=tr[ls].val1;tr[cnt].val2=tr[rs].val2;
}
void work(int cnt,int l,int r,int L,int R,ll k1,ll b1,ll b2){
if(l>=L&&r<=R){
if(k1*l+b1>=tr[cnt].val1+b2){
// cout<<l<<" "<<r<<" "<<tr[cnt].val1<<endl;
add(cnt,l,r,0,b2);
return;
}
if(k1*r+b1<=tr[cnt].val2+b2){
cover(cnt,l,r,k1,b1);
return;
}
}
int mid=(l+r)>>1;
pushdown(cnt,l,r);
if(mid>=L)work(ls,l,mid,L,R,k1,b1,b2);
if(mid<R)work(rs,mid+1,r,L,R,k1,b1,b2);
tr[cnt].val1=tr[ls].val1;tr[cnt].val2=tr[rs].val2;
}
void solve(int now,int l,int r,int tag){
ll num=h[now];
if(ch[now][0])solve(ch[now][0],l,now-1,0),num+=query(1,1,n,now-1);
if(ch[now][1])solve(ch[now][1],now+1,r,1);
upd(1,1,n,now,num);
if(now!=r){
ll k1=h[now],b1=num-h[now]*now,b2=h[now]*(now-l+1);
work(1,1,n,now+1,r,k1,b1,b2);
}
if(tag){
for(int i=0;i<vec1[l].size();++i){
int x=vec1[l][i],idd=id1[l][i];
ans[idd]=query(1,1,n,x);
}
}
}
int main(){
n=rd();Q=rd();
for(int i=1;i<=n;++i)h[i]=rd(),p[0][i]=i;
for(int i=1;(1<<i)<=n;++i)
for(int j=1;j+(1<<i)-1<=n;++j)p[i][j]=_max(p[i-1][j],p[i-1][j+(1<<i-1)]);
for(int i=2;i<=n;++i)lo[i]=lo[i>>1]+1;
for(int i=1;i<=Q;++i){
int l=rd()+1,r=rd()+1;
int mid=RMQ(l,r);
ans1[i]=1ll*(mid-l+1)*h[mid];
if(mid+1<=r)vec1[mid+1].push_back(r),id1[mid+1].push_back(i);
ans2[i]=1ll*(r-mid+1)*h[mid];
if(l<=mid-1)vec2[f(mid-1)].push_back(f(l)),id2[f(mid-1)].push_back(i);
}
build(rot,1,n);
solve(rot,1,n,1);
for(int i=1;i<=Q;++i)ans1[i]+=ans[i],ans[i]=0;
clear(1,1,n);
reverse(h+1,h+n+1);
for(int i=1;(1<<i)<=n;++i)
for(int j=1;j+(1<<i)-1<=n;++j)p[i][j]=_max(p[i-1][j],p[i-1][j+(1<<i-1)]);
for(int i=1;i<=n;++i){
vec1[i]=vec2[i],id1[i]=id2[i];
ch[i][0]=ch[i][1]=0;
}
build(rot,1,n);
solve(rot,1,n,1);
for(int i=1;i<=Q;++i)ans2[i]+=ans[i];
for(int i=1;i<=Q;++i)
printf("%lld\n",min(ans1[i],ans2[i]));
return 0;
}

[IOI2018] meetings 会议的更多相关文章

  1. 洛谷 P5044 - [IOI2018] meetings 会议(笛卡尔树+DP+线段树)

    洛谷题面传送门 一道笛卡尔树的 hot tea. 首先我们考虑一个非常 naive 的区间 DP:\(dp_{l,r}\) 表示区间 \([l,r]\) 的答案,那么我们考虑求出 \([l,r]\) ...

  2. UOJ#410. 【IOI2018】会议

    传送门 首先可以设 \(f[l][r]\) 表示 \([l,r]\) 的答案 设 \(x\) 为区间 \([l,r]\) 的最大值的位置,那么 \(f[l][r] = min(f[l][x-1]+h[ ...

  3. [IOI2018]会议——分治+线段树

    题目链接: [IOI2018]meetings 题目大意:有$n$座山峰,每座山峰有一个高度,有$q$次询问,每次需要确定一个开会山峰使$[l,r]$所有山峰上的人都前往开会山峰,一个山峰的人去开会的 ...

  4. WC2019 题目集

    最近写的一些 WC2019 上讲的一些题.还是怕忘了,写点东西记录一下. LOJ2983 「WC2019」数树 题意 本题包含三个问题: 问题 0:已知两棵 \(n\) 个节点的树的形态(两棵树的节点 ...

  5. github帐户和仓库的创建

    sign up is registration and sign in is logging in for "in" is to enter an existing account ...

  6. 中国计算机学会CCF推荐国际学术会议

    中国计算机学会推荐国际学术会议 (计算机系统与高性能计算) 一.A类 序号 会议简称 会议全称 出版社 网址 1 ASPLOS Architectural Support for Programmin ...

  7. CCF推荐国际学术会议

    类别如下计算机系统与高性能计算,计算机网络,网络与信息安全,软件工程,系统软件与程序设计语言,数据库.数据挖掘与内容检索,计算机科学理论,计算机图形学与多媒体,人工智能与模式识别,人机交互与普适计算, ...

  8. 中国计算机学会CCF推荐国际学术期刊会议(最新版)

    中国计算机学会推荐国际学术期刊会议 2014年12月,中国计算机学会(CCF)启动新一轮<)计算机体系结构/高性能计算/存储系统: )计算机网络:)网络与信息安全:)软件工程/系统软件/程序设计 ...

  9. 401 WebEx会议教程一 —— 参加会议

    · WebEx会议教程一 —— 参加会议 参加他人发起的会议 1.  在邀请邮件中,接受对方的会议邀请: 2.  一般在WebEx会议开始前15分钟时,邮箱客户端会提醒您 (如下图类似提示) 3.   ...

随机推荐

  1. windows7搭建xmapp部署wordpress

    前言 为了学习自动化,在网上搜索资料学习了一下在本机安装xmapp,搭建php环境,本机部署wordpress这个开源项目 内容 主要分成以下几步: 准备安装包,快速安装xmapp 根据实际需求,修改 ...

  2. linux环境,centos7,安装docker

    https://www.jianshu.com/p/2dae7b13ce2f 1.安装依赖包 yum install -y yum-utils device-mapper-persistent-dat ...

  3. 黑群晖DSM 6.x 配置文件grub.cfg修改 mac地址/sn等修改

    新的DSM 6.x配置文件和以前的XPEnoboot的配置文件不一样了,我们可以通过OSFMount虚拟光驱软件打开img后再修改. 安装完成后运行OSFMount点击左下角-Mount new,选择 ...

  4. [转]JavaScript构造函数及原型对象

    JavaScript中没有类的概念,所以其在对象创建方面与面向对象语言有所不同. JS中对象可以定义为”无序属性的集合”.其属性可以包含基本值,对象以及函数.对象实质上就是一组没有特定顺序的值,对象中 ...

  5. python字典使用总结

    作者:python技术人 博客:https://www.cnblogs.com/lpdeboke 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值 key=>value 对用冒号 ...

  6. RD Client、TeamViewer连接主机

    一.使用RD Client连接远程桌面 1.设置本地主机 2.查看电脑ip 3.手机安装RD Client 应用商店下载 Microsoft Remote Desktop PC name填入查询到的I ...

  7. [2019杭电多校第七场][hdu6656]Kejin Player

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6656 题意为从i级花费a元有p的概率升到i+1级,有1-p的概率降到x级(x<i),查询从L级升 ...

  8. 问题 D: 小k的硬币问题

    问题 D: 小k的硬币问题 时间限制: 1 Sec  内存限制: 128 MB提交: 21  解决: 5[提交] [状态] [命题人:jsu_admin] 题目描述 小k和小p一起玩一个游戏,有n堆硬 ...

  9. P5444 [APIO2019]奇怪装置

    传送门 考虑求出最小的循环节 $G$ 使得 $t,t+G$ 得到的数对是一样的 由 $y \equiv t \mod B$ ,得到 $G$ 一定是 $B$ 的倍数,设 $zB=G$,则 $t,t+zB ...

  10. 帝国CMS模板中的多条件筛选方法

    需求:点击某一条目,调出与该条目关键词相关的类似词条数据 要点: 1.帝国CMS灵动标签使用   [e:loop= 2.专题关键词筛选  enewszt 3.SQL语句筛选   select * fr ...