【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]);
}
}
}