原题传送门

题意:给你一个长度为\(n\)的序列\(A\),每次询问修改一个元素(只对当前询问有效),然后让你找到一个不下降序列\(B\),使得这两个序列相应位置之差的平方和最小,并输出这个最小平方和

观察样例说明,发现一个很有趣的性质,\(B\)中数字相同的一段的数字正好是\(A\)中这段数字的平均数

那我们就珂以猜想:最优解的形式一定为分成若干段,每一段的\(B_i\)即取其中\(A_i\)的平均数,同时保证\(B\)的有序性(这篇论文好像有证明)

如何求出最优的\(B\)?我们珂以使用单调栈

考虑枚举\(i\),将\([i,i]\)塞进单调栈中,然后比较栈顶区间的平均值和栈顶下面一个区间的平均值。如果栈顶区间平均值较小,则不满足不下降性质,因此我们将这两个区间合并,然后继续与再下面一个区间进行比较……

如何合并答案?我们只需要维护维护区间元素个数,区间元素和,区间元素平方和即可(像方差那题一样)

接下来考虑如何修改。我们在求整个序列的最优解时,同主席树维护\(A\)每个前缀的单调栈\(pre\)。类似的,从后向前也跑一次,用主席树维护\(A\)每个后缀的单调栈\(suf\)。

假设我们将位置\(pos\)的值修改成了\(val\)。设修改后最优解中\(pos\)所在的区间为\([L,R]\),如果我们能够快速求出\(L,R\)我们就珂以快速得出答案。

注意到单调栈中的一段数的任何前缀平均值都大于去掉该前缀剩余的数的平均值,所以\(L\)为\(pre[pos-1]\)中某个区间的\(L\)或\(pos\),\(R\)为\(suf[pos+1]\)中某个区间的\(R\)或\(pos\)

二分\(R\)的位置,在主席树\(pre[pos-1]\)上二分求出符合的\(L\),判断是否合法。最终找到最小的合法的\(R\),算出\(L\),就珂以求出答案了

#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define mod 998244353
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline int Max(register int a,register int b)
{
return a>b?a:b;
}
int n,m,pre[N],prelen[N],suf[N],suflen[N],tot;
pair<int,int> s[N];
ll inv[N];
struct node{
ll x,y,z;
node(){x=y=z=0;}
node(register ll _x,register ll _y,register ll _z){x=_x,y=_y,z=_z;}
inline ll cal()
{
return (z+mod-(y%mod)*(y%mod)%mod*inv[x]%mod)%mod;
}
}sum[N];
inline node Init(register ll v)
{
return node(1,v,v*v%mod);
}
inline node operator + (node a,node b){return (node){a.x+b.x,a.y+b.y,(a.z+b.z)%mod};}
inline node operator - (node a,node b){return (node){a.x-b.x,a.y-b.y,(a.z-b.z+mod)%mod};}
inline bool operator < (node a,node b){
if(!a.x)
return b.x;
if(!b.x)
return 0;
return (double)a.y/a.x<(double)b.y/b.x;
}
inline node cal(register int l,register int r)
{
if(!l&&!r)
return node(0,0,0);
return sum[r]-sum[l-1];
}
struct seg{
int ls,rs,L,R,ans,Rp;
inline void merge(register seg a,register seg b)
{
L=a.L;
R=Max(a.R,b.R);
ans=(a.ans+b.ans)%mod;
Rp=a.Rp;
}
}tr[N*80];
inline void modify(register int &x,register int l,register int r,register int pos,register int L,register int R)
{
tr[++tot]=tr[x];
x=tot;
if(l==r)
tr[x]=(seg){0,0,L,R,cal(L,R).cal(),R};
else
{
int mid=l+r>>1;
if(pos<=mid)
modify(tr[x].ls,l,mid,pos,L,R);
else
modify(tr[x].rs,mid+1,r,pos,L,R);
tr[x].merge(tr[tr[x].ls],tr[tr[x].rs]);
}
}
inline int query_suf(register int x,register int l,register int r,register int pos)
{
if(l==r)
return tr[x].R;
int mid=l+r>>1;
if(pos<=mid)
return query_suf(tr[x].ls,l,mid,pos);
else
return query_suf(tr[x].rs,mid+1,r,pos);
}
inline int query_pre(register int x,register int l,register int r,register int pos,register node &val)
{
if(r<=pos)
{
node twh=cal(tr[x].L,tr[x].R),tlf=cal(tr[x].L,tr[x].Rp);
if(!(tlf<val+twh))
{
val=val+twh;
return 0;
}
if(l==r)
return tr[x].R;
}
int mid=l+r>>1,res=0;
if(pos>mid)
res=query_pre(tr[x].rs,mid+1,r,pos,val);
if(res)
return res;
return query_pre(tr[x].ls,l,mid,pos,val);
}
int main()
{
n=read(),m=read();
inv[1]=1;
for(register int i=2;i<=n;++i)
inv[i]=inv[mod%i]*(mod-mod/i)%mod;
for(register int i=1;i<=n;++i)
sum[i]=sum[i-1]+Init(read());
for(register int i=1,top=0;i<=n;++i)
{
pre[i]=pre[i-1];
int l=i;
while(top&&!(cal(s[top].first,s[top].second)<cal(l,i)))
modify(pre[i],1,n,top,0,0),l=s[top--].first;
s[prelen[i]=++top]=make_pair(l,i);
modify(pre[i],1,n,top,l,i);
}
for(register int i=n,top=0;i;--i)
{
suf[i]=suf[i+1];
int r=i;
while(top&&!(cal(i,r)<cal(s[top].first,s[top].second)))
modify(suf[i],1,n,top,0,0),r=s[top--].second;
s[suflen[i]=++top]=make_pair(i,r);
modify(suf[i],1,n,top,i,r);
}
write(tr[pre[n]].ans),puts("");
while(m--)
{
int x=read(),y=read();
int l=0,r=suflen[x+1]-1,res=r+1;
while(l<=r)
{
int mid=l+r>>1;
int rp=mid?query_suf(suf[x+1],1,n,suflen[x+1]-mid+1):x;
node val=Init(y)+cal(x+1,rp);
int lp=x>1?query_pre(pre[x-1],1,n,prelen[x-1],val):1;
if(val<cal(rp+1,query_suf(suf[x+1],1,n,suflen[x+1]-mid)))
res=mid,r=mid-1;
else
l=mid+1;
}
int rp=res?query_suf(suf[x+1],1,n,suflen[x+1]-res+1):x;
node val=Init(y)+cal(x+1,rp);
int lp=x>1?query_pre(pre[x-1],1,n,prelen[x-1],val):1;
write((val.cal()+tr[pre[lp]].ans+tr[suf[rp+1]].ans)%mod),puts("");
}
return 0;
}

最新文章

  1. java面向对象六原则一法则
  2. ubuntu安装LAMP环境
  3. 【bzoj1084】最大子矩阵
  4. 2016年12-09php函数
  5. POJ1258Agri-Net(prime基础)
  6. oracle的启动过程(各个模式启动)
  7. 四 mybatis开发dao的方法
  8. webview调用外部浏览器而不是在控件中显示
  9. Session丢失,都是CDN惹的祸
  10. Android 进阶学习:事件分发机制全然解析,带你从源代码的角度彻底理解(上)
  11. BootStrap2学习日记11---单选框多选框
  12. CF 19D - Points 线段树套平衡树
  13. 多线程NSOperation
  14. DEVMODE 结构体
  15. [Protractor] Test Simple Binding With Protractor
  16. android 三级菜单 BaseExpandableListAdapter
  17. eclipse修改默认workspace
  18. win10蓝屏,windbg的使用
  19. Springboot启动后报错【This application has no explicit mapping for /error, so you are seeing this as a fallback&#183;&#183;&#183;&#183;】
  20. 【Linux】python 2.x 升级 python3.x 之后 yum命令出现except OSError, e: ^ SyntaxError: invalid syntax

热门文章

  1. 【JZOJ6246】【20190627】B
  2. APIO2019 游记
  3. CSS样式的引入方式
  4. Eclipse4.9集成Tomcat 9.0.21详细版
  5. 在Eclipse打开css文件时,会自动调用文本编辑器打开,而不是在Eclipse中打开
  6. 剑指offer:把数组排成最小的数
  7. 【Dubbo】带着问题看源码:什么是SPI机制?Dubbo是如何实现的?
  8. Mysql:设置主键自动增长起始值
  9. sql server中raiserror的用法(动态参数传值)
  10. eclipse从git下载的maven项目需要转成maven才可是使用main方法启动