P3203 弹飞绵羊-分块

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;
}
原文地址:https://www.cnblogs.com/BrotherHood/p/13775714.html