题解:P11119 [ROI 2024] 保持连接 (Day 2)
提供一个
显然我们先计算一下每个点下一次跳动的位置,第
我们得到
那么记录
于是不带修改的答案就
接下来考虑修改操作,模拟一下发现会对一段连续的区间的
设覆盖区间
其实还需要考虑连带的影响,也就是满足
那么从
把第
展开显然树状数组单点修改区间查询分别维护
代码十分简单。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) ((x)&(-(x)))
ll n,a[1000005],k,v,ans,res,st,ed,lst;
ll sz[1000005],f[1000005],nxt[1000005];
ll fs[1000005];
void mg(ll x,ll k)
{
for(int i=x;i<=n;i+=lowbit(i)) sz[i]+=k,fs[i]+=f[x]*k;
}
ll qu(ll x)
{
ll res=0;
for(int i=x;i;i-=lowbit(i)) res+=sz[i];
return res;
}
ll qfs(ll x)
{
ll res=0;
for(int i=x;i;i-=lowbit(i)) res+=fs[i];
return res;
}
int main()
{
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
nxt[max(1ll,i-a[i])]=max(nxt[max(1ll,i-a[i])],min(n,i+a[i])+1);
}
for(int i=1;i<=n;i++) nxt[i]=max(nxt[i],nxt[i-1]);
for(int i=n;i>=1;i--) f[i]=f[nxt[i]]+(n-nxt[i]+1);
for(int i=1;i<=n;i++) res+=f[i];
for(int i=1;i<=n;i++) mg(i,1);
ans=res,lst=1;
for(int i=1;i<=n;i++)
{
while(v<n&&nxt[v+1]<=min(n,i+k)) v++;
st=max(1ll,i-k),ed=min(n,i+k)+1;
if(v<st) continue;
while(lst<st) mg(nxt[lst],qu(lst)-qu(lst-1)),lst++;
ll tt=f[ed]+(n-ed+1);
ans=min(ans,res+tt*(qu(v)-qu(st-1))-(qfs(v)-qfs(st-1)));
}
printf("%lld\n",ans);
return 0;
}