P4116 Qtree3
由于刚刚学树剖所以来刷刷水题。不会树剖的同学可以果断右转 : \(blog\)。
这道题的思路就是一直从点 \(x\) 往上跳,一直到 \(root\) (也就是 \(1\))。在其中每一次都查询一遍 \(x\) 到 \(top[x]\) 的最高的黑点。
先随便画一个图 :
其中我们把 \(white\) 定义为 \(val\) 的 \(0\),\(black\) 为 \(1\)。
假设我们从 \(10\) 号节点开始跳。先跳到 \(10\) 的链顶的父亲。
我们会发现 \(min\ dfn=10\) 但是 \(dfn\) 为 \(10\) 的节点还是 \(white\),所以 \(ans=inf\)。
从 \(4\) 往上跳。
\(4\) 是 \(black\),现在是 \(ans=8\) (因为是 \(dfn\))。最后跳到 \(1\) 发现 \(1\) 是 \(black\),结束。
关于线段树的维护,我们要维护的是区间最小值。且所有叶子节点只保留 \(inf\) 或者是 叶子节点的位置 代表 \(white\) 或者 \(black\)。(线段树维护错了让我错了半个板子)
然后有一个优化,如果 \(root\) 是 \(black\),直接输出。(虽然没有数据是这样子的)
Uses math;
var
recf,cnt,size,dfn,dep,top,father,son:array[-1..210000] of longint;
next,reach:array[-1..450000] of longint;
left,right:array[-1..450000] of longint;
tree:array[-1..450000] of int64;
i,n,m,l,r,dfnum,tot,root,order,ans,root_place:longint;
procedure add(l,r:longint);
begin
inc(tot);
reach[tot]:=r;
next[tot]:=cnt[l];
cnt[l]:=tot;
end;
procedure Dfs_1(x:longint);
var i:longint;
begin
size[x]:=1; i:=cnt[x]; size[0]:=-maxlongint div 843;
while i<>-1 do
begin
if dep[reach[i]]=0 then
begin
dep[reach[i]]:=dep[x]+1;
father[reach[i]]:=x;
Dfs_1(reach[i]); inc(size[x],size[reach[i]]);
if size[reach[i]]>size[son[x]] then son[x]:=reach[i];
end;
i:=next[i];
end;
end;
procedure Dfs_2(x,centre:longint);
var i:longint;
begin
inc(dfnum); dfn[x]:=dfnum; recf[dfnum]:=x; top[x]:=centre;
if son[x]=0 then exit; Dfs_2(son[x],centre);
i:=cnt[x];
while i<>-1 do
begin
if (reach[i]<>father[x])and(reach[i]<>son[x]) then Dfs_2(reach[i],reach[i]);
i:=next[i];
end;
end;
procedure Build(k,l,r:longint);
var mid:longint;
begin
left[k]:=l; right[k]:=r;
if (l=r) then begin if l=1 then root_place:=k; tree[k]:=maxlongint; exit; end;
mid:=(l+r) >> 1;
Build(k << 1,l,mid); Build(k << 1+1,mid+1,r);
tree[k]:=maxlongint;
end;
procedure Change(k,x:longint);
var mid:longint;
begin
if left[k]=right[k] then
begin
if tree[k]=maxlongint then tree[k]:=left[k] else tree[k]:=maxlongint;
exit;
end;
mid:=(left[k]+right[k]) >> 1;
if x<=mid then Change(k << 1,x) else Change(k << 1+1,x);
tree[k]:=min(tree[k << 1],tree[k << 1+1]);
end;
function Query(k,x,y:longint):longint;
var mid:longint;
begin
Query:=maxlongint div 84;
if (x<=left[k])and(right[k]<=y) then exit(tree[k]);
mid:=(left[k]+right[k]) >> 1;
if (x<=mid) then Query:=min(Query,Query(k << 1,x,y));
if (y>mid) then Query:=min(Query,Query(k << 1+1,x,y));
end;
procedure Refer(x:longint);
begin
if tree[root_place]<>maxlongint then begin ans:=1; exit; end;
while top[x]<>root do
begin
ans:=min(ans,Query(1,dfn[top[x]],dfn[x]));
x:=father[top[x]];
end;
ans:=min(ans,Query(1,dfn[root],dfn[x]));
if ans>maxlongint div 85 then ans:=-1;
end;
begin
filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1);
read(n,m); root:=1; recf[-1]:=-1;
for i:=1 to n-1 do begin read(l,r); add(l,r); add(r,l); end;
dep[root]:=1; father[root]:=1;
Dfs_1(root); Dfs_2(root,root); Build(1,1,n);
for i:=1 to m do
begin
read(order); ans:=maxlongint div 84;
if order=0 then begin read(l); Change(1,dfn[l]); end;
if order=1 then begin read(l); Refer(l); writeln(recf[ans]); end;
end;
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿