【codevs2333】&【BZOJ2002】弹飞绵羊[HNOI2010](分块)

时间:2023-03-09 16:04:29
【codevs2333】&【BZOJ2002】弹飞绵羊[HNOI2010](分块)

  我其实是在codevs上看到它的题号后才去做这道题的。。。2333。。。

  题目传送门:codevs:http://codevs.cn/problem/2333/  bzoj:http://www.lydsy.com/JudgeOnline/problem.php?id=2002

  题意已经说的很清晰了,蓝鹅……我不会做。

  看题解有两种写法:分块和link-cut tree。但是lct我不会,只能用分块了。

  但是怎么分块呢?

  我们想一下有什么暴力写法。一种是记录每个反弹装置能往后弹多长距离,这样效率是修改O(1)+查询O(n)。另一种是记录从每个反弹装置开始到被弹飞要被弹多少次,这样效率是修改O(n)+查询O(1)。我们可以想一个介于两者之间的做法,比如……把序列平均分成m块,记录每个反弹装置弹到下一个块要弹多少次 和 会弹到下一个块的哪一个装置。这样一来,效率就变成了修改O(n/m)+查询O(m),总时间复杂度就是O(n*(n/m+m))。显然,如果要使效率最快m就取√n。

  接下来就可以打代码+AC了。(代码真心很短)

代码:

var a,ne,x,y:array[..]of longint;
n,m,i,j,k,p,t,q,ans:longint;
begin
read(n); p:=trunc(sqrt(n));
for i:= to n- do begin
read(a[i]); ne[i]:=(i div p+)*p;
end;
for i:= to n- do begin
x[i]:=i; y[i]:=;
while(x[i]<ne[i])and(x[i]<n)do begin
x[i]:=x[i]+a[x[i]]; inc(y[i]);
end;
end;
read(m);
for i:= to m do begin
read(q);
if q= then begin
read(k); ans:=;
while k<n do begin
ans:=ans+y[k]; k:=x[k];
end;
writeln(ans);
end
else begin
read(k,t); a[k]:=t;
for j:=ne[k]- downto ne[k]-p do
if j+a[j]>=ne[j] then begin
x[j]:=j+a[j]; y[j]:=;
end
else begin
x[j]:=x[j+a[j]]; y[j]:=y[j+a[j]]+;
end;
end;
end;
end.

弹飞绵羊

  lct等学了再补吧。。。