【JZOJ4811】排队

Description

这里写图片描述

Solution

明确一点,每个人进入的地方优先级是确定的。

那么我们一开始把所有房间的优先级求出来,塞进堆里。

对于操作一,一个个把有人的房间从堆中弹出。

对于操作二,倍增找到根到当前房间第一个有人的房间,重新加入堆即可。答案即为两房间深度差。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define ll long long
#define N 100001
#define M 200001
#define inf 2147483647
using namespace std;
int to[M],next[M],last[M],num=0;
int fa[N],f[N][18];
int d[N];
int n;
struct node{
    friend bool operator< (node x,node y)
    {
        return x.p>y.p;
    }
    int p,z;
}c[N];
void link(int x,int y)
{
    num++;
    to[num]=y;
    next[num]=last[x];
    last[x]=num;
}
bool bz[N];
int tot=0;
priority_queue<node> q;
priority_queue<int, vector<int>, greater<int> > qn[N];
void find(int x)
{
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        if(v!=fa[x])
        {
            fa[v]=x;
            f[v][0]=x;
            d[v]=d[x]+1;
            qn[x].push(v);
        }
    }
    while(!qn[x].empty())
    {
        find(qn[x].top());
        qn[x].pop();
    }
    node b;
    b.z=x;
    b.p=++tot;
    q.push(b);
    c[x]=b;
}
int main()
{
    int qq;
    cin>>n>>qq;
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        link(x,y);
        link(y,x);
    }
    d[0]=-1;
    find(1);
    fo(j,1,17)
    fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
    while(qq--)
    {
        int op,x;
        scanf("%d %d",&op,&x);
        if(op==1)
        {
            fo(i,1,x-1)
            {
                bz[q.top().z]=1;
                q.pop();
            }
            bz[q.top().z]=1;
            printf("%d\n",q.top().z);
            q.pop();
        }
        else
        {
            int p=x;
            fd(i,17,0)
            if(f[p][i] && bz[f[p][i]]) p=f[p][i];
            bz[p]=0;
            if(p!=x) bz[x]=1;
            printf("%d\n",d[x]-d[p]);
            q.push(c[p]);
        }
    }
}
posted @ 2016-10-05 16:25  sadstone  阅读(33)  评论(0编辑  收藏  举报