题意:
分析:
第一反应是SNOI2017炸弹
这个题我们一看需要对于每一个数都输出一次答案,也就是说我们需要 (log) 或者 (sqrt n) 的复杂度查询每一个点,那么我们思考一下就发现可以通过倍增处理
但是由于这个题每个点能扩展的范围是不一样的,所以倍增迭代时我们需要通过区间查询,找到能向左 (向右) 扩展的最远点坐标,也就是说我们需要一个支持区间操作的数据结构,线段树或者ST表都可以,这里给出ST表的代码
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+ch-48;
ch=getchar();
}
return x*f;
}
const int maxn = 3e5+5;
int log[maxn],l[20][maxn],r[20][maxn],a[maxn];
int n,ans;
struct rmq
{
int c[maxn][20],val[maxn];
int type;
int _max(int x,int y)
{
return (val[x]<val[y]?y:x);
}
void build(int *a,int n,int flag)
{
type=flag;
for(int i=1;i<=n;i++) c[i][0]=i,val[i]=type*a[i];
for(int j=1;j<=log[n];j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
c[i][j]=_max(c[i][j-1],c[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l,int r)
{
int k=log[r-l+1];
return _max(c[l][k],c[r-(1<<k)+1][k]);
}
}ql,qr;
void work()
{
n=read();
for(int i=2;i<=3*n;i++) log[i]=log[i>>1]+1;
for(int i=1;i<=n;i++) a[i]=read(),a[i+2*n]=a[i+n]=a[i];
if(n==1)
{
puts("0");
return ;
}
for(int i=1;i<=3*n;i++) l[0][i]=max(1,i-a[i]),r[0][i]=min(3*n,i+a[i]);
for(int i=0;i<=log[3*n];i++) r[i][3*n]=3*n,l[i][1]=1;
ql.build(l[0],3*n,-1);qr.build(r[0],3*n,1);
for(int j=1;j<=log[3*n];j++)
{
for(int i=1;i<=3*n;i++)
{
int posl=ql.query(l[j-1][i],r[j-1][i]);
int posr=qr.query(l[j-1][i],r[j-1][i]);
l[j][i]=min(l[j-1][posl],l[j-1][posr]);
r[j][i]=max(r[j-1][posl],r[j-1][posr]);
}
}
for(int i=n+1;i<=2*n;i++)
{
int u=i,v=i,ans=0;
for(int j=log[3*n];j>=0;j--)
{
if(max(r[j][u],r[j][v])-min(l[j][u],l[j][v])+1>=n) continue;
int tmpu=ql.query(l[j][u],r[j][v]);
int tmpv=qr.query(l[j][u],r[j][v]);
u=tmpu;v=tmpv;
ans+=(1<<j);
}
ans++;
printf("%d ",ans);
}
}
}
int main()
{
zzc::work();
return 0;
}