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.
posted @ 2018-10-20 15:55  _ARFA  阅读(111)  评论(0编辑  收藏  举报