2022-7-29 #21 P6717
今天花了点时间看完了 淤泥之花与空心石,只能说是神作了!(时长共计 12h,看的非常过瘾)
055 P6717 [CCO2018] Boring Lectures
我们将序列按照 \(k\) 分块,断言答案中至少会有一个块内最大值。
反证法,令最优决策为 \(a,b\),若在同一块,明显把较小的改为块内最大值更优;否则在相邻块,令最大值分别为 \(c,d\),有:
\[a+b>a+c,a+b>b+d\\\Rightarrow b>c,a>d
\]
显然矛盾。
于是维护每一块最大值对应的匹配,放在堆里维护即可,复杂度 \(O((n+q)\log n)\)。
#include<stdio.h>
#include<queue>
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
#define mid (l+r>>1)
using namespace std;
const int maxn=1000005,maxt=maxn<<2;
int n,k,T,bt,stp;
int mx[maxt],a[maxn],bel[maxn],bl[maxn],br[maxn],vis[maxn];
priority_queue< pair<int, pair<int,int> > >q;
inline void pushup(int now){
mx[now]=a[mx[lc(now)]]>a[mx[rc(now)]]? mx[lc(now)]:mx[rc(now)];
}
void build(int l,int r,int now){
if(l==r){
mx[now]=l;
return ;
}
build(l,mid,lc(now)),build(mid+1,r,rc(now)),pushup(now);
}
void modify(int l,int r,int now,int p){
if(l==r)
return ;
if(p<=mid)
modify(l,mid,lc(now),p);
else modify(mid+1,r,rc(now),p);
pushup(now);
}
int query(int l,int r,int now,int L,int R){
if(L<=l&&r<=R)
return mx[now];
if(L<=mid&&mid<R){
int ls=query(l,mid,lc(now),L,R),rs=query(mid+1,r,rc(now),L,R);
return a[ls]>a[rs]? ls:rs;
}
if(L<=mid)
return query(l,mid,lc(now),L,R);
return query(mid+1,r,rc(now),L,R);
}
void answer(){
while(!q.empty()&&vis[q.top().second.first]!=q.top().second.second)
q.pop();
printf("%d\n",q.top().first);
}
void insert(int id){
int p=query(1,n,1,bl[id],br[id]),c=-1;
swap(c,a[p]),modify(1,n,1,p);
vis[id]=stp,q.push(make_pair(c+a[query(1,n,1,max(1,p-k+1),min(n,p+k-1))],make_pair(id,stp)));
swap(c,a[p]),modify(1,n,1,p);
}
int main(){
scanf("%d%d%d",&n,&k,&T),bt=n/k;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=bt;i++)
bl[i]=br[i-1]+1,br[i]=i*k;
if(br[bt]<n)
bt++,bl[bt]=br[bt-1]+1,br[bt]=n;
build(1,n,1);
stp=1;
for(int i=1;i<=bt;i++){
for(int j=bl[i];j<=br[i];j++)
bel[j]=i;
insert(i);
}
answer();
for(int i=1,x,y;i<=T;i++){
scanf("%d%d",&x,&y),a[x]=y,modify(1,n,1,x);
stp++;
if(bel[x]>1)
insert(bel[x]-1);
insert(bel[x]);
if(bel[x]<bt)
insert(bel[x]+1);
answer();
}
return 0;
}