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

本文介绍了一种解决特定类型竞赛编程问题的方法,通过预处理每个节点的优先级,并使用堆进行维护,实现高效的节点管理和更新。此外,还介绍了如何利用倍增技巧处理节点删除操作,确保算法的时间复杂度为log级别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

闪亮登场

题目

Description
这里写图片描述
Input
这里写图片描述
Sample Input

5 4
1 2
1 3
3 4
3 5
1 4
2 4
1 2
2 5

Output
这里写图片描述
Sample Output

3
1
1
2

Data Constraint
这里写图片描述
Hint
这里写图片描述

比赛时の想法

暴力啊QAQ~~~~

正解

首先我们预处理出每一个点的优先级,就是下一个走进来的人会走到当前优先级最小的那个点,那么我们可以用一个堆来维护,每一次进一个人就出一次堆
对于操作2,我们可以用倍增来找到当前位置上面的一个最接近根节点的一个有人的节点,那么就等于这个节点的人直接走到删除的那个节点那里去了
注意在操作2完了之后要维护一下堆
那么两个操作都是log级别的

贴代码

var
    tree,s,ls:array[0..200005]of longint;
    f:array[0..100005,0..18]of longint;
    a,b:array[0..200005,1..2]of longint;
    cp:array[0..20]of longint;
    bz:array[0..100005]of boolean;
    i,j,k,l,m,n,t,x,y,cy,o,p:longint;
procedure qsort(l,r:longint);
var
    i,j,mid,mid1:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,1];
    mid1:=a[(i+j) div 2,2];
    repeat
        while (a[i,1]<mid) or ((a[i,1]=mid) and (a[i,2]<mid1)) do inc(i);
        while (a[j,1]>mid) or ((a[j,1]=mid) and (a[j,2]>mid1)) do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[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 star;
begin
    b[a[1,1],1]:=1;
    for i:=2 to 2*n-2 do
    if a[i,1]<>a[i-1,1] then
    begin
        b[a[i-1,1],2]:=i-1;
        b[a[i,1],1]:=i;
    end;
    b[a[2*n-2,1],2]:=2*n-2;
end;
procedure dfss(x:longint);
var
    i:longint;
begin
    bz[x]:=true;
    for i:=b[x,1] to b[x,2] do
    if (i<>0) and (bz[a[i,2]]=false) then
    begin
        f[a[i,2],0]:=x;
        dfss(a[i,2]);
    end;
    inc(cy);
    tree[cy]:=x;
    s[x]:=cy;
end;
procedure down(x:longint);
begin
    if (s[tree[x*2]]<s[tree[x]]) and (s[tree[x*2]]<s[tree[x*2+1]]) then
    begin
        tree[0]:=tree[x];
        tree[x]:=tree[x*2];
        tree[x*2]:=tree[0];
        down(x*2);
    end else
    if s[tree[x*2+1]]<s[tree[x]] then
    begin
        tree[0]:=tree[x*2+1];
        tree[x*2+1]:=tree[x];
        tree[x]:=tree[0];
        down(x*2+1);
    end;
end;
procedure up(x:longint);
begin
    if x=1 then exit;
    if s[tree[x div 2]]>s[tree[x]] then
    begin
        tree[0]:=tree[x div 2];
        tree[x div 2]:=tree[x];
        tree[x]:=tree[0];
        up(x div 2);
    end;
end;
procedure lca;
var
    i,j:longint;
begin
    for j:=1 to 18 do
        for i:=1 to n do
            f[i,j]:=f[f[i,j-1],j-1];
end;
begin
    assign(input,'t3.in'); reset(input);
    readln(n,t);
    for i:=1 to n-1 do
    begin
        readln(a[i,1],a[i,2]);
        a[i+n-1,1]:=a[i,2];
        a[i+n-1,2]:=a[i,1];
    end;
    qsort(1,2*n-2);
    star;
    cy:=0;
    dfss(1);
    cy:=n;
    s[0]:=maxlongint;
    lca;
    for i:=1 to n do up(i);
    cp[0]:=1;
    for i:=1 to 18 do cp[i]:=cp[i-1]*2;
    fillchar(bz,sizeof(bz),false);
    for i:=1 to t do
    begin
        readln(o,p);
        if o=1 then
        for j:=1 to p do
        begin
            if j=p then writeln(tree[1]);
            bz[tree[1]]:=true;
            tree[1]:=0;
            down(1);
        end else
        begin
            k:=0;
            while f[p,k]>0 do inc(k);
            dec(k);
            x:=p;
            y:=0;
            for j:=k downto 0 do
            if (f[x,j]>0) and (bz[f[x,j]]=true) then
            begin
                x:=f[x,j];
                y:=y+cp[j];
            end;
            for j:=cy downto 1 do
                if tree[j]=0 then break;
            tree[j]:=x;
            bz[x]:=false;
            up(j);
            writeln(y);
        end;
    end;
    close(input);
end.

完美谢幕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值