P3203 弹飞绵羊-分块
观察数据范围,发现可以分块。只需要处理每个点跳出所在块后的位置和次数即可。目的是为了加速查询并降低修改复杂度。
对于修改,重构整个块内信息即可。
时间复杂度正确的一批
具体实现也挺简单。注意重构时从后往前贡献即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=2e5+10;
int n,N,out[maxn],cos[maxn],a[maxn],belong[maxn],l[maxn],r[maxn];
void sudo(int l,int r){for(int i=r;i>=l;i--)if(i+a[i]>n or belong[i+a[i]]!=belong[i])out[i]=i+a[i],cos[i]=1;else out[i]=out[i+a[i]],cos[i]=1+cos[i+a[i]];}
inline void work(){
n=read();
N=sqrt(n);
for(int i=1;i<=n;i++)
belong[i]=(i-1)/N+1;
for(int i=1;i<=n;i++){
if(!l[belong[i]])l[belong[i]]=i;
r[belong[i]]=i;
}
for(int i=1;i<=n;i++)a[i]=read();
sudo(1,n);
int q=read();
while(q--){
if(read()==1){
int sum=0,pos=read()+1;
while(pos<=n)sum+=cos[pos],pos=out[pos];
printf("%d
",sum);
}else{
int pos=read()+1;
a[pos]=read();
sudo(l[belong[pos]],r[belong[pos]]);
}
}
}
}
signed main(){
star::work();
return 0;
}
那我要是想知道最后弹飞前的点在哪呢?
我们只需要在重构的时候记录一下从哪来的就好了。
双倍经验:CF13E
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=2e5+10;
int n,N,out[maxn],last[maxn],cos[maxn],a[maxn],belong[maxn],l[maxn],r[maxn];
void sudo(int l,int r){for(int i=r;i>=l;i--)if(i+a[i]>min(n,r))out[i]=i+a[i],last[i]=i,cos[i]=1;else out[i]=out[i+a[i]],last[i]=last[i+a[i]],cos[i]=1+cos[i+a[i]];}
inline void work(){
n=read();
int q=read();
N=sqrt(n);
for(int i=1;i<=n;i++)
belong[i]=(i-1)/N+1;
for(int i=1;i<=n;i++){
if(!l[belong[i]])l[belong[i]]=i;
r[belong[i]]=i;
}
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=belong[n];i++)sudo(l[i],r[i]);
while(q--){
if(read()==1){
int sum,pos,lpos;
sum=0,pos=lpos=read();
while(pos<=n)sum+=cos[pos],lpos=last[pos],pos=out[pos];
printf("%d %d
",lpos,sum);
}else{
int pos=read();
a[pos]=read();
sudo(l[belong[pos]],r[belong[pos]]);
}
}
}
}
signed main(){
star::work();
return 0;
}