码迷,mamicode.com
首页 > 其他好文 > 详细

[HNOI2010]BOUNCE 弹飞绵羊

时间:2017-10-26 23:03:58      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:++   0.00   cpp   lin   style   bounce   else   highlight   def   

题目:BZOJ2002、洛谷P3203、codevs2333。

题目大意:有n个装置,编号0~n-1。每个装置有一个弹跳系数,第i个装置可以把羊弹到第$i+k_i$个装置上,然后继续弹。如果这个位置没有装置,则停止弹。

现在有m个操作,可以问你一只绵羊在某点开始弹,弹多少次才能结束,也可以修改一个装置的弹跳系数。

解题思路:分块。

一般都是每块分成$\sqrt{n}$个(最后一个可能不同),分成$\sqrt{n}$或$\sqrt{n}+1$块。

设jp[i]表示从这个点跳到另一个块的某个点要多少下,nxt[i]表示从i开始跳,跳到另一个块后,跳到的节点的编号。则可以发现,更新一个弹跳系数,只会变化该块内的答案(一个点可能跳到相同块内一个点)。

然后记录下每个块的起点,更新答案时一个一个更新即可(注意倒着更新)。

输出弹跳次数则更加简单,每次累计jp[i],然后令i=nxt[i]即可。

更新答案最多涉及一整个块,输出弹跳次数最多每个块有一个节点被访问,所以一次处理的时间复杂度为$O(\sqrt{n})$。

则总时间复杂度为$O(m\sqrt{n})$。

当然您也可以用LCT秒了这道题。

C++ Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<cmath>
#define N 200020
int n,size,jp[N],nxt[N],k[N],l[505],inbk[N],blocks;
inline int readint(){
	char c=getchar();
	for(;!isdigit(c);c=getchar());
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^‘0‘);
	return d;
}
int ask(int s){
	int ans=0;
	while(s!=-1){
		ans+=jp[s];
		s=nxt[s];
	}
	return ans;
}
int main(){
	n=readint();
	size=(int)(sqrt(n)+0.00000001);
	blocks=0;
	l[0]=0;
	for(int i=0;i<n;++i){
		k[i]=readint();
		inbk[i]=blocks;
		if(i%size==size-1)l[++blocks]=i+1;
	}
	if(n%size)++blocks;
	memset(nxt,-1,sizeof nxt);
	for(int i=n-1;i>=0;--i){
		if(i+k[i]>=n)jp[i]=1;else
		if(inbk[i]==inbk[i+k[i]])
		jp[i]=jp[i+k[i]]+1,nxt[i]=nxt[i+k[i]];else
		jp[i]=1,nxt[i]=i+k[i];
	}
	for(int m=readint();m--;){
		int f=readint();
		if(f==1)printf("%d\n",ask(readint()));else{
			int x=readint();
			k[x]=readint();
			for(int i=x;i>=l[inbk[x]];--i)
			if(inbk[i]==inbk[i+k[i]])jp[i]=jp[i+k[i]]+1,nxt[i]=nxt[i+k[i]];else
			jp[i]=1,nxt[i]=i+k[i];
		}
	}
	return 0;
}

 

[HNOI2010]BOUNCE 弹飞绵羊

标签:++   0.00   cpp   lin   style   bounce   else   highlight   def   

原文地址:http://www.cnblogs.com/Mrsrz/p/7739242.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!