正题

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


题目大意

给出一个长度为nnn的序列hhh,定义dis(x,y)=max{hi}(x≤i≤y)dis(x,y)=max\{h_i\}(x\leq i\leq y)dis(x,y)=max{hi​}(x≤i≤y)。

qqq次询问给出一个区间[L,R][L,R][L,R],找到一个x∈[L,R]x\in[L,R]x∈[L,R],最小化∑i=LRdis(i,x)\sum_{i=L}^Rdis(i,x)∑i=LR​dis(i,x)的值。

1≤n,q≤750000,1≤hi≤1091\leq n,q\leq 750000,1\leq h_i\leq 10^91≤n,q≤750000,1≤hi​≤109


解题思路

先考虑暴力的做法,记fl,rf_{l,r}fl,r​表示区间[l,r][l,r][l,r]的答案,那么我们找出[l,r][l,r][l,r]的任意一个最大值的位置xxx,要么是左边跨过这个值要么是右边跨过这个值,也就是
fl,r=min{fl,x−1+(r−x+1)×hx,fx+1,r+(x−l+1)×hx}f_{l,r}=min\{f_{l,x-1}+(r-x+1)\times h_x,f_{x+1,r}+(x-l+1)\times h_x\}fl,r​=min{fl,x−1​+(r−x+1)×hx​,fx+1,r​+(x−l+1)×hx​}
考虑怎么优化这个转移,因为关系到这个区间的最大值,所以我们考虑在笛卡尔树上计算答案。

对于每个询问[L,R][L,R][L,R],我们先找到这个区间的最大值xxx把它拆分成[L,x][L,x][L,x]和[x,R][x,R][x,R]的询问。

先考虑形如[x,R][x,R][x,R]这一部分的询问,因为这一部分都满足最大值在最左边。

对于每个笛卡尔树上的节点midmidmid,记它的区间[l,r][l,r][l,r],我们考虑维护所有的fl,xf_{l,x}fl,x​其中x∈[l,r]x\in[l,r]x∈[l,r]。

那么我们怎么转移这个东西

  • 对于x∈[l,mid−1]x\in[l,mid-1]x∈[l,mid−1],fl,xf_{l,x}fl,x​代表的意义不变。
  • 对于x=midx=midx=mid,fl,mid=fl,mid−1+hmidf_{l,mid}=f_{l,mid-1}+h_{mid}fl,mid​=fl,mid−1​+hmid​,因为midmidmid是最高点,在这个点聚合显然不合适。
  • 对于x∈[mid+1,r]x\in[mid+1,r]x∈[mid+1,r],fl,x=min{fl,mid+hmid×(x−mid),fmid+1,x+hmid×(mid−l+1)}f_{l,x}=min\{f_{l,mid}+h_{mid}\times (x-mid),f_{mid+1,x}+h_{mid}\times (mid-l+1)\}fl,x​=min{fl,mid​+hmid​×(x−mid),fmid+1,x​+hmid​×(mid−l+1)}

麻烦的是后面那个东西,我们考虑在线段树上维护所有的f?,xf_{?,x}f?,x​(???根据处理到的节点改变)。

然后发现fl,mid+hmid×(x−mid)f_{l,mid}+h_{mid}\times (x-mid)fl,mid​+hmid​×(x−mid)根据xxx的变化稳定增加hmidh_{mid}hmid​,而fmid+1,x+hmid×(mid−l+1)f_{mid+1,x}+h_{mid}\times (mid-l+1)fmid+1,x​+hmid​×(mid−l+1)这个玩意每次的增量是fmid+1,x−fmid+1,x−1f_{mid+1,x}-f_{mid+1,x-1}fmid+1,x​−fmid+1,x−1​,显然是不会超过hmidh_{mid}hmid​的。

所以选择它们两个的决策之间存在一个交点,我们可以二分这个位置。考虑这个加等差序列和区间推平操作都是要在线段树上搞的,所以我们直接顺手在线段树上二分就好了,因为这个的原因我们要记录一下左端点和右端点的权值。

时间复杂度:O((n+q)log⁡n)O(\ (n+q)\log n\ )O( (n+q)logn )


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const ll N=760000;
struct node{ll r,w,id;
};
ll n,m,lg[N],h[N],f[N][20],ans[N];
ll ql[N],qr[N];vector<node> q[N];
struct SegTree{#define M N<<2ll w[M],k[M],c[M],wl[M],wr[M];void Clear(){memset(w,0,sizeof(w));memset(wl,0,sizeof(wl));memset(wr,0,sizeof(wr));memset(k,0,sizeof(k));memset(c,0,sizeof(c));}void Setw(ll x,ll val){w[x]=wl[x]=wr[x]=val;k[x]=c[x]=0;return;}void Setk(ll x,ll val){wl[x]+=val;wr[x]+=val;k[x]+=val;return;}void Downdata(ll x,ll L,ll R){if(w[x]>0)Setw(x*2,w[x]),Setw(x*2+1,w[x]),w[x]=-1;if(k[x])Setk(x*2,k[x]),Setk(x*2+1,k[x]),k[x]=0;if(c[x]){ll mid=(L+R)>>1;k[x*2+1]+=c[x]*(mid-L+1);wr[x*2]+=c[x]*(mid-L);wl[x*2+1]+=c[x]*(mid-L+1);wr[x*2+1]+=c[x]*(R-L);c[x*2]+=c[x];c[x*2+1]+=c[x];c[x]=0;}return;}void Change(ll x,ll L,ll R,ll l,ll r,ll val){if(L==l&&R==r){Setw(x,val);return;}ll mid=(L+R)>>1;Downdata(x,L,R);if(r<=mid)Change(x*2,L,mid,l,r,val);else if(l>mid)Change(x*2+1,mid+1,R,l,r,val);else Change(x*2,L,mid,l,mid,val),Change(x*2+1,mid+1,R,mid+1,r,val);wl[x]=wl[x*2];wr[x]=wr[x*2+1];return;}void Update(ll x,ll L,ll R,ll l,ll r,ll ks,ll cs){if(L==l&&R==r){Setk(x,ks);c[x]+=cs;wr[x]+=(R-L)*cs;return;}ll mid=(L+R)>>1;Downdata(x,L,R);if(r<=mid)Update(x*2,L,mid,l,r,ks,cs);else if(l>mid)Update(x*2+1,mid+1,R,l,r,ks,cs);else Update(x*2,L,mid,l,mid,ks,cs),Update(x*2+1,mid+1,R,mid+1,r,ks,cs);wl[x]=wl[x*2];wr[x]=wr[x*2+1];return;}ll Ask(ll x,ll L,ll R,ll pos){if(L==R)return wr[x];ll mid=(L+R)>>1;Downdata(x,L,R);if(pos<=mid)return Ask(x*2,L,mid,pos);return Ask(x*2+1,mid+1,R,pos);}void Solve(ll x,ll L,ll R,ll l,ll r,ll k1,ll b1,ll b2){if(L==l&&R==r){if(b1>=wl[x]+b2){Setk(x,b2);return;}if(k1*(R-L)+b1<=wr[x]+b2){Setw(x,b1);wr[x]+=k1*(R-L);c[x]+=k1;return;}}ll mid=(L+R)>>1;Downdata(x,L,R);if(r<=mid)Solve(x*2,L,mid,l,r,k1,b1,b2);else if(l>mid) Solve(x*2+1,mid+1,R,l,r,k1,b1,b2);else Solve(x*2,L,mid,l,mid,k1,b1,b2),Solve(x*2+1,mid+1,R,mid+1,r,k1,b1+k1*(mid-l+1),b2);wl[x]=wl[x*2];wr[x]=wr[x*2+1];return;}#undef M
}T;
ll RMQ(ll l,ll r){ll z=lg[r-l+1];l=f[l][z];r=f[r-(1<<z)+1][z];return (h[l]<h[r])?r:l;
}
void solve(ll L,ll R){if(L>R)return;ll x=RMQ(L,R);solve(L,x-1);solve(x+1,R);for(ll i=0;i<q[x].size();i++)ans[q[x][i].id]=min(ans[q[x][i].id],q[x][i].w+T.Ask(1,1,n,q[x][i].r));ll f=(x>L)?T.Ask(1,1,n,x-1):0;f+=h[x];T.Change(1,1,n,x,x,f);if(x<R)T.Solve(1,1,n,x+1,R,h[x],f+h[x],(x-L+1)*h[x]);return;
}
signed main()
{scanf("%lld%lld",&n,&m);for(ll i=2;i<=n;i++)lg[i]=lg[i>>1]+1;for(ll i=1;i<=n;i++)scanf("%lld",&h[i]),f[i][0]=i;memset(ans,0x3f,sizeof(ans));    for(ll j=1;(1<<j)<=n;j++)for(ll i=1;i+(1<<j)-1<=n;i++){ll a=f[i][j-1],b=f[i+(1<<j-1)][j-1];f[i][j]=(h[a]<h[b])?b:a;}for(ll i=1;i<=m;i++){scanf("%lld%lld",&ql[i],&qr[i]);ql[i]++;qr[i]++;ll x=RMQ(ql[i],qr[i]);q[x].push_back((node){qr[i],(x-ql[i]+1)*h[x],i});}solve(1,n);reverse(h+1,h+1+n);for(ll i=1;i<=n;i++)q[i].clear();for(ll j=1;(1<<j)<=n;j++)for(ll i=1;i+(1<<j)-1<=n;i++){ll a=f[i][j-1],b=f[i+(1<<j-1)][j-1];f[i][j]=(h[a]<h[b])?b:a;}for(ll i=1;i<=m;i++){ql[i]=n-ql[i]+1;qr[i]=n-qr[i]+1;swap(ql[i],qr[i]);ll x=RMQ(ql[i],qr[i]);q[x].push_back((node){qr[i],(x-ql[i]+1)*h[x],i});}T.Clear();solve(1,n);for(ll i=1;i<=m;i++)printf("%lld\n",ans[i]);return 0;
}

P5044-[IOI2018] meetings 会议【dp,笛卡尔树,线段树二分】相关推荐

  1. 【IOI2018】会议【笛卡尔树】【dp】【线段树】

    题意:长度为nnn的序列,qqq次询问,每次给定一个区间,钦定区间中的一个位置xxx,使得区间所有点 与xxx之间的最大值(含端点) 之和 最小,输出最小值. n,q≤7.5×105n,q\leq7. ...

  2. 树套树-线段树套平衡树

    作用 线段树的作用是区间修改和查询,平衡树的作用是查询第k大,k的排名,前驱,后继.这两个结合起来,就变成了可以区间修改和查询第k大,k的排名,前驱,后继的数据结构:树套树-线段树套平衡树. 实现 先 ...

  3. 牛客 - sequence(笛卡尔树+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a 和数列 b ,求 题目分析:不算难的题目,对于每个 a[ i ] 求一下贡献然后维护最大值就好,具体思路就是,先找出每个 a[ i ] 左 ...

  4. YbtOJ#752-最优分组【笛卡尔树,线段树】

    正题 题目链接:http://www.ybtoj.com.cn/problem/752 题目大意 nnn个人,每个人有cic_ici​和did_idi​分别表示这个人所在的队伍的最少/最多人数. 然后 ...

  5. P4755-Beautiful Pair【笛卡尔树,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4755 题目大意 nnn个数字的一个序列,求有多少个点对i,ji,ji,j满足ai×aj≤max{ak}(k∈[l ...

  6. HDU 6155 Subsequence Count (DP、线性代数、线段树)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6155 题解 DP+线代好题.(考场上过多时间刚前两题,没怎么想这题--) 首先列出一个DP式: 设\( ...

  7. 群赛 ZOJ3741(dp) ZOJ3911(线段树)

    zoj3741 简单dp.wa了两个小时,中间改了好多细节.后来还是不对,参考了别人的代码,发现一个致命问题,初始化的时候,不是每种状态都能直接达到的.初始化成-1. (题目有个小坑,0<=L& ...

  8. 2019长沙学院新生赛(A水,B水,C(整除分块),D水,E(巧数学),F(二分+bfs),H(换根dp),I(线段树)J(dp+倍增+lca))

    A-XOR SUM 通过简单观察得知连续四个数的异或值就是等于0,暴力找出左区间和右区间就可以了,最多跑四个单位 0^1^2^3==0   4^5^6^7=0 #include<bits/std ...

  9. 线段树 ---- 线段树维护线段相加+滑动变长窗口 2021牛客多校第7场 F xay loves trees

    题目大意: 给你两个大小相同的树但是形状不一定一样 叫你选出最大的子集,满足下面两个条件 在第一颗树上是一条链 在第二颗树上任意两个点都不是祖先关系 解题思路: 首先我们现在第二颗树上面把每个点的df ...

最新文章

  1. 数据库系统(一)——数据查询
  2. 自然语言处理中的Attention Model:是什么以及为什么[一]
  3. 运维祈求不宕机_[国庆特辑] 程序员应该求谁保佑才能保证不宕机?
  4. 【Java】函数式接口与Lambda表达式
  5. perl-regexp_使用Regexp :: Common在Perl中轻松进行数据验证
  6. android studio怎么输入中文,Android studio 模拟器中输入中文
  7. linux 网络有关的5个命令
  8. 94. autoload
  9. tp3.2 or 查询 (同字段)
  10. MFC教程(Visual C++ 6.0)|合集 |更新中
  11. python构建带数字的古诗词数据集
  12. Ubuntu18.04 wifi不稳定
  13. 心理学-墨菲定律 个人笔记
  14. web攻击:XSS跨站脚本
  15. 服务器被攻击了怎么办?海外服务器有什么有特点?网址或者APP被攻击了怎么办?
  16. R语言基础数据分析—单因素方差分析
  17. python数据采集培训
  18. AWS 中文入门开发教学 28- 链接Rout53和freenom - 设置托管区(Hosted Zone)和名字服务器(NS)
  19. gcc: error trying to exec ‘cc1plus‘: execvp: no such file or directory
  20. 2022第四届长安杯检材一wp

热门文章

  1. 基于应用日志的扫描器检测实践
  2. 宝塔linux面板假设nextcloud,宝塔面板部署NextCloud(14.0.3)逐一解决后台安全及设置警告...
  3. confluencejira集成_Jira Service Desk使用教程之如何将Jira Cloud与Confluence集成?
  4. redis在linux搭建集群,Linux/Centos 7 redis4 集群搭建
  5. flask取mysql数据很慢_[flask 优化] 由flask-bootstrap,flask-moment引起的访问速度慢的原因及解决办法...
  6. 浙江省2021年英语高考成绩查询,浙江高考成绩查询、志愿填报时间公布!
  7. android 强制下线功能,Android学习之基础知识八—Android广播机制实践(实现强制下线功能)...
  8. py2exe for python3_使用Py2Exe for Python3创建自己的exe程序
  9. .net html5页面缓存,详解HTML5中的manifest缓存使用
  10. leetcode377. 组合总和 Ⅳ