正题

P5044


题目大意

给出一个序列a,设 dist(x,y)=max⁡i=xyaidist(x,y)=\max_{i=x}^ya_idist(x,y)=maxi=xy​ai​,有m个询问,对于每个询问,给出 l,r,让你找一个点x(l≤x≤r)(l\leq x\leq r)(l≤x≤r),使得 ∑i=lrdist(i,x)\sum_{i=l}^rdist(i,x)∑i=lr​dist(i,x) 最小


解题思路

设 fi,jf_{i,j}fi,j​ 为区间 [l,r] 的答案,那么得到区间最大值x后,可以按如下转移

fl,r=min⁡(fl,x−1+ax×(r−x+1),fx+1,r+ax×(x−l+1))f_{l,r}=\min(f_{l,x-1}+a_x\times(r-x+1),f_{x+1,r}+a_x\times(x-l+1))fl,r​=min(fl,x−1​+ax​×(r−x+1),fx+1,r​+ax​×(x−l+1))

考虑如何优化

考虑对该数列建立笛卡尔树

对于一个查询 [l,r] ,求出最大点x,那么可以把当前询问拆成 [l,x-1] 和 [x+1,r]

那么对于笛卡尔树上的一个点x(子树范围为 [l,r]),只需维护 [l,x-1],[l+1,x-1]…[x-1,x-1] 和 [x+1,r],[x+1,r-1]…[x+1,x+1] 这些状态

那么可以用两个线段树,分别维护遍历到当前点时每个点到子树最左/右端的答案

对于左子树的点,考虑从左子树选还是从右子树选,可以把右子树选的贡献差分一下,然后线段树上二分找分界点修改决策(即哪些点选左子树,哪些点选右子树,单调性易证),右子树同理

遍历完笛卡尔树中左右子树后,计算最大点为当前点的询问,记下答案后再往回走

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


code

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 750100
#define mp make_pair
#define fs first
#define sn second
using namespace std;
ll n,t,l,r,lg[N],h[N],f[N][25],ans[N];
vector<pair<pair<ll,ll>,ll> >q[N];
struct Tree
{#define ls x*2#define rs x*2+1ll lazy[N<<2],b[N<<2],k[N<<2],lm[N<<2],rm[N<<2];void push_up(ll x){lm[x]=lm[ls];rm[x]=rm[rs];return;}void get(ll x,ll l,ll r,ll bb,ll kk){b[x]+=bb;k[x]+=kk;lm[x]+=bb+kk*l;rm[x]+=bb+kk*r;return;}void clr(ll x){lazy[x]=1;k[x]=b[x]=lm[x]=rm[x]=0;return;}void push_down(ll x,ll l,ll r){if(lazy[x]){clr(ls);clr(rs);lazy[x]=0;}ll mid=l+r>>1;get(ls,l,mid,b[x],k[x]);get(rs,mid+1,r,b[x],k[x]);b[x]=k[x]=0;return;}void add(ll x,ll L,ll R,ll l,ll r,ll y){if(L==l&&R==r){get(x,l,r,y,0);return;}push_down(x,L,R);ll mid=L+R>>1;if(r<=mid)add(ls,L,mid,l,r,y);else if(l>mid)add(rs,mid+1,R,l,r,y);else add(ls,L,mid,l,mid,y),add(rs,mid+1,R,mid+1,r,y);push_up(x);return;}void change(ll x,ll L,ll R,ll l,ll r,ll y,ll z){if(L==l&&R==r){ll gl=y+z*l,gr=y+z*r;if(gl>=lm[x]&&gr>=rm[x])return;//分界点在中间就二分下去else if(gl<=lm[x]&&gr<=rm[x]){clr(x);get(x,l,r,y,z);return;}}push_down(x,L,R);ll mid=L+R>>1;if(r<=mid)change(ls,L,mid,l,r,y,z);else if(l>mid)change(rs,mid+1,R,l,r,y,z);else change(ls,L,mid,l,mid,y,z),change(rs,mid+1,R,mid+1,r,y,z);push_up(x);return;}ll ask(ll x,ll l,ll r,ll y){if(l==r)return lm[x];push_down(x,l,r);ll mid=l+r>>1;if(y<=mid)return ask(ls,l,mid,y);else return ask(rs,mid+1,r,y);}
}TL,TR;
ll get(ll l,ll r)
{ll g=lg[r-l+1];if(h[f[l][g]]>=h[f[r-(1<<g)+1][g]])return f[l][g];else return f[r-(1<<g)+1][g];
}
void solve(ll l,ll r)
{ll x=get(l,r);if(l<x)solve(l,x-1);if(x<r)solve(x+1,r);for(ll i=0;i<q[x].size();++i){ll lans=0,rans=0,L=q[x][i].fs.fs,R=q[x][i].fs.sn;if(L<x)lans=TR.ask(1,1,n,L);if(x<R)rans=TL.ask(1,1,n,R);ans[q[x][i].sn]=min(lans+h[x]*(R-x+1),rans+h[x]*(x-L+1));}ll gl=h[x],gr=h[x];if(l<x)gl+=TL.ask(1,1,n,x-1);if(x<r)gr+=TR.ask(1,1,n,x+1);TL.add(1,1,n,x,x,gl);TR.add(1,1,n,x,x,gr);if(l<x){TR.add(1,1,n,l,x-1,h[x]*(r-x+1));//加上右子树的点走到左边的贡献TR.change(1,1,n,l,x-1,gr+h[x]*x,-h[x]);//在右边选的贡献}if(x<r){TL.add(1,1,n,x+1,r,h[x]*(x-l+1));TL.change(1,1,n,x+1,r,gl-h[x]*x,h[x]);}return;
}
int main()
{scanf("%lld%lld",&n,&t);for(ll i=1;i<=n;++i){scanf("%lld",&h[i]);f[i][0]=i;}for(ll i=2;i<=n;++i)lg[i]=lg[i>>1]+1;for(ll j=1;j<=20;++j)for(ll i=1;i<=n-(1<<j)+1;++i)if(h[f[i][j-1]]>=h[f[i+(1<<j-1)][j-1]])f[i][j]=f[i][j-1];else f[i][j]=f[i+(1<<j-1)][j-1];for(ll i=1;i<=t;++i){scanf("%lld%lld",&l,&r);l++;r++;q[get(l,r)].push_back(mp(mp(l,r),i));}solve(1,n);for(ll i=1;i<=t;++i)printf("%lld\n",ans[i]);return 0;
}

【笛卡尔树】【线段树】meetings 会议(P5044)相关推荐

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

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

  2. P5044-[IOI2018] meetings 会议【dp,笛卡尔树,线段树二分】

    正题 题目链接:https://www.luogu.com.cn/problem/P5044 题目大意 给出一个长度为nnn的序列hhh,定义dis(x,y)=max{hi}(x≤i≤y)dis(x, ...

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

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

  7. BZOJ 3685: 普通van Emde Boas树( 线段树 )

    建颗权值线段树就行了...连离散化都不用... 没加读入优化就TLE, 加了就A掉了...而且还快了接近1/4.... ---------------------------------------- ...

  8. 2021CCPC(桂林) - Suffix Automaton(后缀树+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,再给出 qqq 次询问,每次询问需要输出本质不同第 kkk 小的子串的起止位置.如果有多个答案,输出起点最小的那个. 本题规定字符串大小 ...

  9. HDU - 4417 Super Mario(主席树/线段树+离线)

    题目链接:点击查看 题目大意:给出由 n 个数的数列,再给出 m 次查询,每次查询需要输出 [ l , r ] 内小于等于 h 的数有多少个 题目分析:大晚上睡不着觉随便做做题,发现这个题目原来可以用 ...

  10. jzoj3338-[NOI2013模拟]法法塔的奖励【权值线段树,线段树合并】

    正题 题目大意 一棵树,对于每个点,求从任何一个在该点的子树为头,以该点为结尾的序列必须选择这个点的最长不降子序列. 解题思路 首先我们使用权值线段树计算答案每个点(l,r,w)(l,r,w)(l,r ...

最新文章

  1. set RowCount 与 top n
  2. Android成长日记-使用ViewFlipper实现屏幕切换动画效果
  3. 35张非常精美的爱情桌面壁纸资源(下篇)
  4. 原创 MySQL探秘(八):基于Redo Log和Undo Log的MySQL崩溃恢复流程(一致性)
  5. 本地java【动态监听】zk集群节点变化
  6. java 泛化_Java语言class类用法及泛化(详解)
  7. tomcat启动正常,但是访问项目时,404. Eclipse没有正确部署工程项目
  8. Percona XtraBackup
  9. ajax blockUI
  10. Galaxy Note8面世,“三维立体”发布会传递怎样的信号?
  11. APP开发者常用的4种推广渠道
  12. 第二届翼支付杯大数据建模大赛-信用风险用户识别Baseline 线上0.65+稳进复赛
  13. 可用的公开 RTSP/ RTMP 在线视频流资源地址(亲测可行)
  14. SSM框架项目实践,leetcode46
  15. Creo 4.0 软件安装教程
  16. (Java) 实现打印菱形图案
  17. 《信息化项目文档模板二——项目启动会文档模板》
  18. TensorFlow入门之二:tensorflow手写数字识别
  19. 用python整个活(4)——哥德巴赫猜想
  20. 『2048』苏晓辉の转专业面试作品 · 纪念品

热门文章

  1. linux perl模块检测,Linux有问必答:如何用Perl检测Linux的发行版本
  2. mysql 表与表之间的条件比对_值得收藏 | 一份最完整的MySQL规范
  3. 错误代码1500什么意思_啊早安打工人是什么梗???
  4. cv2.imread读取图像结果none_python cv2.imread 读取中文路径的图片返回为None的问题
  5. relation does not exist报错是什么意思_为什么Zookeeper天生就是一副分布式锁的胚子?...
  6. deb包如何改支持12系统_对一个deb包的解压、修改、重新打包全过程方法
  7. [MyBatisPlus]入门案例
  8. [Java基础]接口组成(默认方法,静态方法,私有方法)
  9. [蓝桥杯2017决赛]数位和-模拟(水题)
  10. JAVA JFrame画图基础和事件监听