也是一道保序回归的题,但思路不同于论文中模板题

考虑两个开口向上的二次函数$f(x)$和$g(x)$,求任意实数$x,y$满足$x\le y$且最小化$f(x)+g(y)$,这个最小值可以分类讨论求出:

1.若$f(x)$最小值位置小于等于$g(x)$的最小值位置,显然都取最小值即可;

2.若$f(x)$最小值位置大于$g(x)$的最小值位置,再对$x$的位置分类讨论——

(1)若$x$的位置在$g(x)$最小值的右侧,根据二次函数的性质应取$y=x$;

(2)若$x$的位置在$g(x)$最小值的左侧,显然$y$应取$g(x)$的最小值,那么$x$也应等于$y$

由此,我们可以得到此时最小值必然为$x=y$

(事实上,对于任意在最小值两侧单调的函数$f(x)$和$g(x)$,都具有此性质)

每一个位置就是一个这样的二次函数,对于相邻两个二次函数也就是求上述实数对$(x,y)$

考虑一个暴力的做法:不断找到相邻两个二次函数,使得前者的最小值大于后者的最小值,并根据第2种情况,将两者合并为同一个二次函数$f(x)+g(x)$,最终每一个二次函数最小值之和即为答案

关于合并的顺序是否影响答案,由于每一次合并都保证答案最优,因此最终答案也一定最优,当然也可以证(kou)明(hu)不会影响答案

所谓影响答案,影响的是相邻两点“是否合并”这件事情的不同,同时合并后最小值一定是向中间靠的,因此合并后一定“更可以合并”,由此不难证明合并顺序不影响答案

这一做法的具体实现可以通过单调栈,将前面的二次函数都求出,每次插入一个函数并考虑是否需要与栈顶的二次函数合并即可

对于修改$(x,y)$,先对单调栈作预处理,即用主席树维护出每一个前缀或后缀的单调栈的区间和(对于删除只需要记录栈大小即可)

根据合并顺序的任意,可以先将$[1,x)$和$(x,n]$这两段都合并(合并后的信息在主席树中维护),之后考虑求出左右最终与$x$合并的段数$l$和$r$(注意这里方便表述使用了数量,而代码中用的是下标)

称一对$(l,r)$合法当且仅当将这$l+r+1$个二次函数(包括$x$自己)合并后,与左右两个单调栈内剩下的二次函数最小值单调不下降

合法的$(l,r)$具有单调性,具体来说就是$(l,r)$合法则$(l+1,r)$和$(l,r+1)$都合法

但合法仅仅只是必要条件,问题在于:可以通过与右边单调的部分去合并,使得其值增大,从而与左边原来不单调的部分也单调,这样是不正确的

换言之,我们需要保证最后一次对$l$和$r$的合并都是不单调的合并,即对于$(l,r-1)$,右端点不单调;对于$(l-1,r)$,左端点不单调

具体实现中,为了方便二分,可以先选择$(l,r)$合法以及$(l,r-1)$右端点不单调这两个条件,确定出最小的$r$(对于确定的$l$),之后判定$(l,r)$左端点是否单调(要求单调)

接下来,在外面再套一层对$l$的二分,同样找到最小的合法的$l$即保证了$(l-1,r)$左端点不单调的条件

如果二分后用主席树做复杂度为$o(q\log^{3}n)$,在$r$上的二分可以直接在主席树上二分,因此复杂度为$o(q\log^{2}n)$

  1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 100005
4 #define mod 998244353
5 #define ll long long
6 #define mid (l+r>>1)
7 int n,m,x,y,top,ans,rt[2][N],sz[2][N];
8 int ksm(int n,int m){
9 int s=n,ans=1;
10 while (m){
11 if (m&1)ans=1LL*ans*s%mod;
12 s=1LL*s*s%mod;
13 m>>=1;
14 }
15 return ans;
16 }
17 struct fun{
18 int a,c;
19 ll b;
20 bool operator < (const fun &k)const{
21 //-b/(2*a)<-k.b/(2*k.a)
22 return b*k.a>a*k.b;
23 }
24 fun operator + (const fun &k)const{
25 return fun{a+k.a,(c+k.c)%mod,b+k.b};
26 }
27 fun operator - (const fun &k)const{
28 return fun{a-k.a,(c+mod-k.c)%mod,b-k.b};
29 }
30 int get_min(){
31 int bb=(b%mod+mod)%mod;
32 return (c+mod-1LL*bb*bb%mod*ksm(4*a,mod-2)%mod)%mod;
33 }
34 }a[N],st[N];
35 struct Seg{
36 int V,ls[N*40],rs[N*40],sum[N*40];
37 fun right[N*40],f[N*40];
38 int New(int k){
39 V++;
40 ls[V]=ls[k];
41 rs[V]=rs[k];
42 sum[V]=sum[k];
43 right[V]=right[k];
44 f[V]=f[k];
45 return V;
46 }
47 void update(int &k,int l,int r,int x,fun y){
48 k=New(k);
49 if (l==r){
50 sum[k]=y.get_min();
51 right[k]=f[k]=y;
52 return;
53 }
54 if (x<=mid)update(ls[k],l,mid,x,y);
55 else update(rs[k],mid+1,r,x,y);
56 if (right[rs[k]].a)right[k]=right[rs[k]];
57 else right[k]=right[ls[k]];
58 sum[k]=(sum[ls[k]]+sum[rs[k]])%mod;
59 f[k]=f[ls[k]]+f[rs[k]];
60 }
61 fun query_fun(int k,int l,int r,int x,int y){
62 if ((!k)||(l>y)||(x>r))return {0,0,0};
63 if ((x<=l)&&(r<=y))return f[k];
64 return query_fun(ls[k],l,mid,x,y)+query_fun(rs[k],mid+1,r,x,y);
65 }
66 int query_sum(int k,int l,int r,int x,int y){
67 if ((!k)||(l>y)||(x>r))return 0;
68 if ((x<=l)&&(r<=y))return sum[k];
69 return (query_sum(ls[k],l,mid,x,y)+query_sum(rs[k],mid+1,r,x,y))%mod;
70 }
71 int find(int k,int l,int r,fun x){
72 if (l==r)return l;
73 if (x+f[rs[k]]<right[ls[k]])return find(rs[k],mid+1,r,x);
74 return find(ls[k],l,mid,x+f[rs[k]]);
75 }
76 }T[2];
77 bool check(int l,int x,int y){
78 fun o={1,(int)(1LL*y*y%mod),-2*y};
79 o=o+T[0].query_fun(rt[0][x-1],1,n,l,sz[0][x-1]);
80 int r=T[1].find(rt[1][x+1],1,n,o);
81 if (o<T[1].right[rt[1][x+1]])r=sz[1][x+1]+1;
82 o=o+T[1].query_fun(rt[1][x+1],1,n,r,sz[1][x+1]);
83 return ((l==1)||(T[0].query_fun(rt[0][x-1],1,n,l-1,l-1)<o));
84 }
85 int calc(int l,int x,int y){
86 fun o={1,(int)(1LL*y*y%mod),-2*y};
87 o=o+T[0].query_fun(rt[0][x-1],1,n,l,sz[0][x-1]);
88 int r=T[1].find(rt[1][x+1],1,n,o);
89 if (o<T[1].right[rt[1][x+1]])r=sz[1][x+1]+1;
90 o=o+T[1].query_fun(rt[1][x+1],1,n,r,sz[1][x+1]);
91 int ans=o.get_min();
92 ans=(ans+T[0].query_sum(rt[0][x-1],1,n,1,l-1))%mod;
93 ans=(ans+T[1].query_sum(rt[1][x+1],1,n,1,r-1))%mod;
94 return ans;
95 }
96 int main(){
97 scanf("%d%d",&n,&m);
98 for(int i=1;i<=n;i++){
99 scanf("%d",&x);
100 a[i]=fun{1,(int)(1LL*x*x%mod),-2*x};
101 }
102 for(int i=1;i<=n;i++){
103 st[++top]=a[i];
104 rt[0][i]=rt[0][i-1];
105 while ((top>1)&&(st[top]<st[top-1])){
106 T[0].update(rt[0][i],1,n,top,{0,0,0});
107 st[top-1]=st[top-1]+st[top];
108 top--;
109 }
110 sz[0][i]=top;
111 T[0].update(rt[0][i],1,n,sz[0][i],st[top]);
112 }
113 top=0;
114 for(int i=n;i;i--){
115 st[++top]=a[i];
116 rt[1][i]=rt[1][i+1];
117 while ((top>1)&&(st[top-1]<st[top])){
118 T[1].update(rt[1][i],1,n,top,{0,0,0});
119 st[top-1]=st[top-1]+st[top];
120 top--;
121 }
122 sz[1][i]=top;
123 T[1].update(rt[1][i],1,n,sz[1][i],st[top]);
124 }
125 printf("%d\n",T[0].sum[rt[0][n]]);
126 for(int i=1;i<=m;i++){
127 scanf("%d%d",&x,&y);
128 int l=1,r=sz[0][x-1]+1;
129 while (l<r){
130 int mi=(l+r+1>>1);
131 if (check(mi,x,y))l=mi;
132 else r=mi-1;
133 }
134 printf("%d\n",calc(l,x,y));
135 }
136 }

[luogu5294]序列的更多相关文章

  1. 【Luogu5294】[HNOI2019]序列

    题目链接 题意 给定一个序列,要求将它改造成一个非降序列,修改一个数的代价为其改变量的平方. 最小化总代价. 另有\(Q\) 次询问,每次修改一个位置上的数.(询问之间独立,互不影响) Sol 神仙 ...

  2. 【夯实PHP基础】UML序列图总结

    原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...

  3. Windows10-UWP中设备序列显示不同XAML的三种方式[3]

    阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...

  4. 软件工程里的UML序列图的概念和总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 软件工程的一般开发过程:愿景分析.业务建模,需求分析,健壮性设计,关键设计,最终设计,实现…… 时序图也叫序列图(交互图),属于软件 ...

  5. python序列,字典备忘

    初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...

  6. BZOJ 1251: 序列终结者 [splay]

    1251: 序列终结者 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3778  Solved: 1583[Submit][Status][Discu ...

  7. 最长不下降序列nlogn算法

    显然n方算法在比赛中是没有什么用的(不会这么容易就过的),所以nlogn的算法尤为重要. 分析: 开2个数组,一个a记原数,f[k]表示长度为f的不下降子序列末尾元素的最小值,tot表示当前已知的最长 ...

  8. [LeetCode] Sequence Reconstruction 序列重建

    Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. Th ...

  9. [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列

    Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...

随机推荐

  1. VS2017离线安装QT插件出错:未能正确加载VSIX包

    问题现象: 问题已解决,忘记截图了 出现原因:可能是自己离线安装,安装版本与不符合当前VS吧.记得当时下载了一个最新的版本.重新卸载当前插件,再装一个合适版本即可 http://download.qt ...

  2. CF123E Maze(期望dp,树形dp,式子)

    题目大意: 给你一棵树,边权都是1,每一个点有一个是起点的概率和一个是终点的概率,你将以起点为根,开始在树上随机dfs,每到一个点,就会将他的所有儿子随机打乱成序列,然后按照那个随机顺序走完,直到走到 ...

  3. postman如何解决下个接口依赖上一个接口数据

    解决思路:将上一个接口返回的数据保存起来,然后提供下个接口使用,postman中通过设置全局变量来保存数据 步骤1:在Tests中添加如下图js代码. var jsondata = JSON.pars ...

  4. web全栈后台权限管理系统(VUE+ElementUi+nodeJs+koa2)

    web全栈后台权限管理系统(VUE+ElementUi+nodeJs+koa2) 主要技术 前端 vue 全家桶 ElementUI 后端 Node.js Koa2 Mongoess 数据库 mong ...

  5. python socket 基本使用

    socket通常也叫做"套接字",用于连接server client,是一个通信链的句柄,应用程序通常通过套接字向网络发出请求或应答网络请求. 就像python 处理file一样: ...

  6. Linux常用命令,查看树形结构、删除目录(文件夹)、创建文件、删除文件或目录、复制文件或目录(文件夹)、移动、查看文件内容、权限操作

    5.查看树结构(tree) 通常情况下系统未安装该命令,需要yum install -y tree安装 直接使⽤tree显示深度太多,⼀般会使⽤ -L选项⼿⼯设定⽬录深度 格式:tree -L n [ ...

  7. 微软Windows11安卓子系统已支持运行APK 应用(附手把手详细安装攻略)怎么安装安卓/如何安装安卓应用/支持多窗口多任务

    ​​ 10 月 21 日消息,微软博客宣称,Windows 11 上 安卓子系统运行 Android  应用程序的第一个预览版现已提供给美国 Beta 频道的 Windows 内部人员.但现在通过教程 ...

  8. 三分钟极速体验:Java版人脸检测

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. IDEA 激活码,最新激活码,亲测有效,持续更新(2021.10.26)

    这里整理了一份 IntelliJ IDEA的最新激活码,持续更新 获取链接:[腾讯文档]分享白嫖JB Account和激活码(并附带破解工具) https://docs.qq.com/doc/DVnB ...

  10. 一个C#开发搭建Android框架的心路历程

    前言 Java框架实在是太多了,因为是初学乍练,所以,只好以百度为标准选择框架了. Java的框架文章太难写了,因为他引用了太多框架,而没一个框架都有很繁琐的配置,把每个框架都写一遍,就等于写书了:所 ...