P3203 [HNOI2010]弹飞绵羊

分块以后就很简单了,可以直接搞。

首先预处理,求出一个 \(get_i\) 和相对应的 \(pace_i\) 代表从 \(i\) 点一直弹到下一个块的地方和步数。那我们查询的时候每一次都是可以在 \(\sqrt{N}\) 的次数内弹到终点的。

关于修改,就是块里面可能会有一个点 \(j\) 会弹到 \(i\) 这里,借助 \(i\) 来弹到下一个块。这样子就保证了修改在整个块里面,操作同样是 \(\sqrt{N}\) 的。

然后注意弹出了以后要判一下边界,不然会溢出导致很多神奇的东西。

// luogu-judger-enable-o2
var
    bounce,get,pace:array [-1..200007] of longint;
    node_num,block_num,mode,ans,l,k,i,j,n,m:longint;

function Locate(node:longint):longint;begin exit((node-1) div node_num+1); end;

procedure Ready;
begin
    read(n); node_num:=trunc(sqrt(n)); block_num:=Locate(n);
    for i := 1 to n do read(bounce[i]); read(m);

    for i:=n downto 1 do 
    begin
        l:=Locate(i)*node_num;
        if (i+bounce[i]>n) then begin get[i]:=0; pace[i]:=1; continue; end;
        if (i+bounce[i]>l) then begin get[i]:=i+bounce[i]; pace[i]:=1; end else 
        begin get[i]:=get[i+bounce[i]]; pace[i]:=pace[i+bounce[i]]+1; end;
    end;
end;

begin
    Ready;
    for i:=1 to m do 
    begin 
    	read(mode);
        if mode=1 then 
        begin
        	ans:=0; read(l); inc(l); j:=l;
            while j>0 do begin inc(ans,pace[j]); j:=get[j]; end;
            writeln(ans);
        end else 
        begin
            read(l,k); inc(l);  bounce[l] := k;
            for j:=l downto(Locate(l)-1)*node_num+1 do 
            begin
            	if (j+bounce[j]>n) then begin get[j]:=0; pace[j]:=1; continue; end;
                if (j+bounce[j]>Locate(l)*node_num) then begin get[j]:=j+bounce[j]; pace[j]:=1; end else 
                begin get[j]:=get[j+bounce[j]]; pace[j]:=pace[j+bounce[j]]+1; end;
            end;
        end;
    end;
end.
posted @ 2019-01-25 22:10  _ARFA  阅读(177)  评论(0编辑  收藏  举报