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

28 篇文章 0 订阅
6 篇文章 0 订阅

Description

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

Analysis

首先,有一个显然却极其重要的性质:每个点的优先级是固定的。即,每次新来一个人必定去优先级最高的没人的点。
所以可以一遍dfs求出每个点的优先级。
考虑你要每次找出一个优先级最高的没人的点,同时还要支持让一个有人的房间重新变成没人的房间。你想到了什么?
没错,就是堆。
第二问显然可以倍增一下,整个过程用堆维护。

Code

#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v) for(int i=0;i<a[v].size();i++)
using namespace std;
const int N=100010;
int n,tot,pd[N],b[N],c[N],heap[N*4],dep[N],f[N][20];
bool bz[N];
vector<int> a[N];
bool cmp(int x,int y)
{
    return pd[x]<pd[y];
}
void dfs(int v,int fr,int d)
{
    f[v][0]=fr,dep[v]=d;
    efo(i,v)
    {
        int u=a[v][i];
        if(u==fr) continue;
        dfs(u,v,d+1);
    }
    pd[v]=++tot;
}
void add(int v)
{
    heap[++tot]=v;
    for(int son=tot;son>1 && b[heap[son]]<b[heap[son/2]];son/=2) swap(heap[son],heap[son/2]);
}
int get()
{
    int t=heap[1];
    heap[1]=heap[tot];
    heap[tot--]=0;
    for(int v=1;;)
    {
        int ls=v+v,rs=v+v+1,son;
        if(!(b[heap[v]]>b[heap[ls]] && ls<=tot || b[heap[v]]>b[heap[rs]] && rs<=tot)) break;
        if(rs>tot || b[heap[ls]]<b[heap[rs]])
            son=ls;
        else
            son=rs;
        swap(heap[v],heap[son]);
        v=son;
    }
    return t;
}
int up(int v)
{
    fd(i,log2(dep[v]),0)
        if(bz[f[v][i]]) v=f[v][i];
    return v;
}
int main()
{
    int _,u,v,op,x,pos;
    scanf("%d %d",&n,&_);
    fo(i,1,n-1)
    {
        scanf("%d %d",&u,&v);
        a[u].push_back(v);
        a[v].push_back(u);
    }
    fo(i,1,n) c[i]=i,sort(a[i].begin(),a[i].end());
    dfs(1,1,1);
    fo(j,1,log2(n))
        fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
    sort(c+1,c+n+1,cmp);
    fo(i,1,n) b[c[i]]=i;
    tot=0;
    fo(i,1,n) add(i);
    while(_--)
    {
        scanf("%d %d",&op,&x);
        if(op==1)
        {
            fo(i,1,x)
                bz[pos=get()]=1;
            printf("%d\n",pos);
        }
        else
        {
            int y=up(x);
            printf("%d\n",dep[x]-dep[y]);
            add(y);bz[y]=0;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值