【NOIP提高组五校联考】排队

2 篇文章 0 订阅
2 篇文章 0 订阅

Description

这里写图片描述

Solution

因为每一个房间的优先级是固定的,所以可以预处理出每个房间的优先级,以此作为凭证把它插入堆中,很显然较优先的房间若是空的就一定会选取到,那么一次插入若干个人,就进行同样次数的取顶操作。记录那些点已经被占用了,显然被占用的房间一定是连续的,只要找到开头,第二问就能轻松解决,倍增就可以快速解决了。(比赛的时候想太多了,以为可能经过操作后被占用房间会断开,所以没有打倍增……)

Code

var
    next,data:array[0..200000] of longint;
    last,l1,l2,t,dfn,de,p:array[0..100000] of longint;
    f:array[0..100000,0..20] of longint;
    n,m,op,q,x,y,i,j,sum,num:longint;
procedure ins(x,y:longint);
begin
    inc(sum);
    data[sum]:=y;
    next[sum]:=last[x];
    last[x]:=sum;
end;
procedure up(x:longint);
begin
    if x div 2=0 then exit;
    if dfn[t[x]]<dfn[t[x div 2]] then
    begin
        t[0]:=t[x];t[x]:=t[x div 2];t[x div 2]:=t[0];
        up(x div 2);
        exit;
    end;
end;
procedure down(x:longint);
var s:longint;
begin
    s:=x;
    if (x*2<=sum)and(dfn[t[s]]>dfn[t[x*2]]) then s:=x*2;
    if (x*2+1<=sum)and(dfn[t[s]]>dfn[t[x*2+1]]) then s:=x*2+1;
    if s=x then exit;
    t[0]:=t[x];t[x]:=t[s];t[s]:=t[0];
    down(s);
end;
procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
    i:=l;j:=r;
    mid:=t[(i+j)div 2];
    repeat
        while t[i]>mid do inc(i);
        while mid>t[j] do dec(j);
        if i<=j then
        begin
            t[0]:=t[i];t[i]:=t[j];t[j]:=t[0];
            inc(i); dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r);
    if l<j then qsort(l,j);
end;
procedure dfs(x,fa:longint);
var i:longint;
begin
    i:=last[x];num:=0;
    while i<>0 do
    begin
        if data[i]<>fa then
        begin
            inc(num);
            t[num]:=data[i];
        end;
        i:=next[i];
    end;
    qsort(1,num);
    for i:=1 to num do
    begin
        inc(sum);
        l1[sum]:=x;l2[sum]:=t[i];
    end;
    i:=last[x];
    while i<>0 do
    begin
        if data[i]<>fa then dfs(data[i],x);
        i:=next[i];
    end;
end;
procedure deal(x,fa,deep:longint);
var i:longint;
begin
    de[x]:=deep;
    f[x,0]:=fa; i:=1;
    while f[f[x,i-1],i-1]<>0 do
    begin
        f[x,i]:=f[f[x,i-1],i-1];
        inc(i);
    end;
    i:=last[x];
    while i<>0 do
    begin
        deal(data[i],x,deep+1);
        i:=next[i];
    end;
    inc(num);dfn[x]:=num;
    inc(sum);t[sum]:=x;
    up(sum);
end;
function jump(x:longint):longint;
var i:longint;
begin
    jump:=x;
    while p[f[jump,0]]=1 do
    begin
        i:=1;
        while p[f[jump,i]]=1 do inc(i);
        dec(i);
        jump:=f[jump,i];
    end;
    exit(jump);
end;
begin
    readln(n,m);
    for i:=1 to n-1 do
    begin
        readln(x,y);
        ins(x,y); ins(y,x);
    end;
    sum:=0;
    dfs(1,0);
    fillchar(data,sizeof(data),0);
    fillchar(last,sizeof(last),0);
    fillchar(next,sizeof(next),0);
    fillchar(t,sizeof(t),0);
    sum:=0;
    for i:=1 to n-1 do ins(l1[i],l2[i]);
    sum:=0;num:=0;
    deal(1,0,1);
    for i:=1 to m do
    begin
        readln(op,q);
        case op of
            1:
            for j:=1 to q do
            begin
                if j=q then writeln(t[1]);
                p[t[1]]:=1;t[1]:=0;
                t[0]:=t[sum];t[sum]:=t[1];t[1]:=t[0];
                dec(sum); down(1);
            end;
            2:
            begin
                x:=jump(q);
                writeln(de[q]-de[x]);
                p[x]:=0;
                inc(sum);
                t[sum]:=x;
                up(sum);
            end;
        end;
    end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值