题解
- 首先,我们很容易就可以发现,每个人的走法就是后序遍历的走法
- 询问删掉一个人之后又多少个人变化,也就是该点到根路径上人的数量
- 那么我们就可以用堆维护房间,然后用倍增往上跳找人数
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 #include <vector>
5 #include <cmath>
6 #include <algorithm>
7 using namespace std;
8 const int N=100010;
9 int n,t,tot,cnt,ans,dfx[N],d[N],p[N],heap[N*4],deep[N],f[N][20];
10 bool bz[N];
11 vector<int> a[N];
12 bool cmp(int x,int y) { return dfx[x]<dfx[y]; }
13 void dfs(int x,int fa)
14 {
15 f[x][0]=fa,deep[x]=deep[fa]+1;
16 for (int i=0;i<a[x].size();i++) if (a[x][i]!=fa) dfs(a[x][i],x);
17 dfx[x]=++cnt;
18 }
19 void insert(int x)
20 {
21 heap[++tot]=x;
22 for (int i=tot;i>1&&p[heap[i]]<p[heap[i/2]];i/=2) swap(heap[i],heap[i/2]);
23 }
24 int get()
25 {
26 int x=heap[1],i=1;
27 heap[1]=heap[tot],heap[tot--]=0;
28 while (1)
29 {
30 int l=i*2,r=i*2+1,m;
31 if (!(p[heap[i]]>p[heap[l]]&&l<=tot||p[heap[i]]>p[heap[r]]&&r<=tot)) break;
32 if (r>tot||p[heap[l]]<p[heap[r]]) m=l; else m=r;
33 swap(heap[i],heap[m]),i=m;
34 }
35 return x;
36 }
37 int jump(int x)
38 {
39 for (int i=log2(deep[x]);i>=0;i--) if (bz[f[x][i]]) x=f[x][i];
40 return x;
41 }
42 int main()
43 {
44 scanf("%d%d",&n,&t);
45 for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),a[x].push_back(y),a[y].push_back(x);
46 for (int i=1;i<=n;i++) d[i]=i,sort(a[i].begin(),a[i].end());
47 dfs(1,0);
48 for (int j=1;j<=log2(n);j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
49 sort(d+1,d+n+1,cmp);
50 for (int i=1;i<=n;i++) p[d[i]]=i;
51 for (int i=1;i<=n;i++) insert(i);
52 for (int i=1,x,y,op;i<=t;i++)
53 {
54 scanf("%d%d",&op,&x);
55 if (op==1)
56 {
57 for (;x;x--) bz[ans=get()]=1;
58 printf("%d\n",ans);
59 }
60 else printf("%d\n",deep[x]-deep[y=jump(x)]),insert(y),bz[y]=0;
61 }
62 }