JZOJ 4811 【NOIP2016提高A组五校联考1】排队

排队

题目描述

这里写图片描述
这里写图片描述
这里写图片描述

数据范围

这里写图片描述

题解

dfs 遍历一遍整棵树,先遍历编号大的儿子,再遍历编号小的儿子,得出 dfs 序(简称 dfx ),定义优先级更优仅当 dfx 更大时,那么在放人的时候先放入优先级更优的空房间显然是满足题目条件的。

那么我们可以用一个堆来维护空房间(大顶堆,按照优先级来维护,一开始堆内只有叶子节点),每次把堆顶取出(即当前优先级最优的空房间),如果可以把它的父亲放入堆中,那就放进堆内维护一下。(可以把一个节点的父亲放入堆中当且仅当他的父亲不在堆内且他的父亲为空房间)
以上是 1 号操作的做法。

对于2号操作,我们发现,移除操作只对 x 的第一个父亲为空房间的祖先有影响,这个节点将会被释放,由被占有的房间变成空房间,这个我们可以用倍增实现,通过深度算出答案,并将此被释放的节点放入堆中,并维护。

2号操作无疑不会超时,那我们分析一下 1 号操作的时间复杂度。最多只会放入n+ t 个人,一次维护操作耗时log n ,总时间复杂度为(n+ t ) log n <script type="math/tex" id="MathJax-Element-85">n</script>,显然不会超时。

Code(Pascal)

var
    fz,fd:array[-1..210000] of boolean;
    fa,en,dfx,yx,d,sd:array[-1..210000] of int64;
    bj:array[0..210000,1..2] of int64;
    f:array[0..110000,0..20] of int64;
    n,m,x,cqy,l,i,op,t,kkk,ans,p,wz:longint;
procedure qsort(l,r:longint);
    var
        i,j,m,mm:longint;
    begin
        i:=l;
        j:=r;
        m:=bj[(l+r) div 2,1];
        mm:=bj[(l+r) div 2,2];
        repeat
            while (bj[i,1]<m) or ((bj[i,1]=m) and (bj[i,2]>mm)) do inc(i);
            while (bj[j,1]>m) or ((bj[j,1]=m) and (bj[j,2]<mm)) do dec(j);
            if i<=j then
            begin
                bj[0]:=bj[i];
                bj[i]:=bj[j];
                bj[j]:=bj[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
procedure up(o:longint);
    var
        y:longint;
    begin
        while (o>1) and (yx[d[o]]>yx[d[o div 2]]) do
        begin
            y:=o div 2;
            d[0]:=d[o];
            d[o]:=d[y];
            d[y]:=d[0];
            o:=y;
        end;
    end;
procedure down(o:longint);
    var
        y:longint;
    begin
        while ((o*2<=p) and (yx[d[o*2]]>yx[d[o]])) or
        ((o*2+1<=p) and (yx[d[o*2+1]]>yx[d[o]])) do
        begin
            y:=o*2;
            if (o*2+1<=p) and (yx[d[o*2+1]]>yx[d[o*2]]) then inc(y);
            d[0]:=d[y];
            d[y]:=d[o];
            d[o]:=d[0];
            o:=y;
        end;
    end;
procedure dg(o:longint);
    var
        i,l,m:longint;
    begin
        inc(cqy);
        dfx[cqy]:=o;
        yx[o]:=cqy;
        l:=0;
        while f[f[o,l],l]>0 do
        begin
            f[o,l+1]:=f[f[o,l],l];
            inc(l);
        end;
        for i:=en[o-1]+1 to en[o] do
        if fa[bj[i,2]]=0 then
        begin
            f[bj[i,2],0]:=o;
            fa[bj[i,2]]:=o;
            sd[bj[i,2]]:=sd[o]+1;
            dg(bj[i,2]);
        end;
        if en[o-1]+1=en[o] then
        begin
            inc(p);
            fd[o]:=true;
            d[p]:=o;
            up(p);
        end;
    end;
function bz(o:longint):longint;
    var
        i:longint;
    begin
        i:=20;
        while i>=0 do
        begin
            if fz[f[o,i]] then o:=f[o,i];
            dec(i);
        end;
        exit(o);
    end;
begin
    readln(n,t);
    for i:=1 to n-1 do
    begin
        readln(bj[i*2-1,1],bj[i*2-1,2]);
        bj[i*2,1]:=bj[i*2-1,2];
        bj[i*2,2]:=bj[i*2-1,1];
        inc(en[bj[i*2,1]]);
        inc(en[bj[i*2,2]]);
    end;
    for i:=2 to n do
    en[i]:=en[i-1]+en[i];
    qsort(1,2*n-2);
    fa[1]:=-1;
    dg(1);
    yx[-1]:=-1;
    for i:=1 to t do
    begin
        readln(op,x);
        if op=1 then
        for l:=1 to x do
        begin
            fz[d[1]]:=true;
            fd[d[1]]:=true;
            ans:=d[1];
            if (fz[fa[d[1]]]=false) and (fd[fa[d[1]]]=false) then
            begin
                fd[fa[d[1]]]:=true;
                d[1]:=fa[d[1]];
                down(1);
            end
            else
            begin
                d[1]:=-1;
                down(1);
            end;
        end
        else
        begin
            wz:=bz(x);
            fz[wz]:=false;
            writeln(sd[x]-sd[wz]);
            fd[wz]:=true;
            inc(p);
            d[p]:=wz;
            up(p);
        end;
        if op=1 then writeln(ans);
    end;
end.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值