Description
Input
第一行n和t,点数和询问数
接下来n-1行为边
最后t行为询问,如题目描述
Output
对于每个询问输出答案
Sample Input
5 4
1 2
1 3
3 4
3 5
1 4
2 4
1 2
2 5
Sample Output
3
1
1
2
Data Constraint
n<=100000
Solution
首先可以求出每个点的dfs序,从小到大就是每个人进入的顺序。
那么用小根堆维护即可。
对于询问1,就是依次退出堆顶
对于询问2,就是查出这个点到根中有点的数量,倍增求出即可,然后把最上面的那个点加会堆中
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
using namespace std;
int n,tot=0,dfn[N],d[N],f[N][20],bz[N],e[N];
struct node{
int x,y;
};
node a[N*2],b[N];
bool cnt(node x,node y){return (x.x<y.x)||((x.x==y.x)&&(x.y<y.y));}
void dg(int x,int fa)
{
fo(i,b[x].x,b[x].y) if(a[i].y!=fa) f[a[i].y][0]=x,dg(a[i].y,x);
dfn[x]=++tot;e[tot]=x;
}
void up(int x)
{
if(x<=1) return;
if(d[x]<d[x/2]) swap(d[x],d[x/2]),up(x/2);else return;
}
void down(int x)
{
int y=x*2;if(d[x*2]>d[x*2+1]&&y<tot) y++;
if(y>tot) return;
if(d[x]>d[y]) swap(d[x],d[y]),down(y);else return;
}
int fd(int x)
{
int ans=0;
for(int i=16;i>=0;i--) if(bz[f[x][i]]) x=f[x][i],ans+=1<<i;
printf("%d\n",ans);return x;
}
int main()
{
int ac;scanf("%d%d",&n,&ac);
fo(i,1,n-1) scanf("%d%d",&a[i].x,&a[i].y),a[i+n-1].x=a[i].y,a[i+n-1].y=a[i].x;
sort(a+1,a+n+n-1,cnt);fo(i,1,n*2-1) if(a[i].x!=a[i-1].x) b[a[i-1].x].y=i-1,b[a[i].x].x=i;
dg(1,0);tot=0;fo(i,1,n) d[++tot]=dfn[i],up(tot);
fo(j,1,16)
fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
for(;ac;ac--)
{
int jy,x;scanf("%d%d",&jy,&x);
if(jy==1)
{
for(;x>1;x--) bz[e[d[1]]]=1,swap(d[tot--],d[1]),down(1);
printf("%d\n",e[d[1]]);bz[e[d[1]]]=1,swap(d[tot--],d[1]),down(1);
}
else
{
int k=fd(x);d[++tot]=dfn[k];bz[k]=0;up(tot);
}
}
}