【题目大意】
对于给定的一棵树(初始全为白点),执行两种询问
1.每次询问给这棵树填充x个黑点,填充规则:每个黑点从根节点(1)往叶子节点走(只能走白点)(如果有多个可行路径,则走到比编号最小的子节点),直到不能走为止,最后停留的位置被染为黑色,并输出第x个黑点最后停留的位置
2.将x位置的黑点染为白色,其余黑点按照1规则重新填充,问有多少个黑点改变了位置
题目保证询问合法
【题解】
首先询问2应该比较好想到,每个黑点只会影响到是他的祖先的黑点(自行yy),所以只需树上倍增,每次询问找到x往上走最后一个黑点祖先j,ans=d[j]-d[x](d为深度)并把j染为白色
现在思考询问1,对于询问1不难想到,每个点都有自己的优先级(按照规则自行yy),一个点要填充时当且仅当所有优先级比它低的点都已被填充,所以就可以用一个堆维护剩余未填充点的优先级,每次填充堆顶的节点
当然我是用一个比较迷幻的dfs,不难想到,若要填充一个节点,当且仅当他的所有儿子节点都被填满,以及他的编号比他小的兄弟都被填满,所以就可以用一个dfs实现填充(填充前先给每个点连出的边排序,为了使得编号小的儿子节点被更早访问),比较zz的填充方法就是每次从节点1往下dfs遇到不能染色的点就不进入,当一个点所有的儿子节点都填满时在给他染色(我最后就是这样打,虽然我打的那个是我接下来要说的正确的dfs),不难想到,这个方法随便出个数据就可以卡掉了(会超时啊233)(虽然并没存在这种数据),然后在深入往下思考,可以dfs时会把许多一万年都不会被染色的点遍历一万次(比如根节点),所以我们可以改变一下dfs的顺序,每次从优先级最高的白点开始dfs,然后进行普通的dfs,再加上一个模拟回溯的过程,就是记录当前这个节点是不是由它的父亲走过来的(因为我们dfs的第一个节点并不是根节点),如果不是(比如他可能从它的儿子走过来)就dfs它的父亲节点(这里就是从儿子走到父亲),这样就可以实现一个模拟回溯的过程。
总之讲的有点迷幻(我也觉得好迷幻)
详见代码
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <ctime>
#include <vector>
using namespace std;
int i,j,k,l,m,n,t,s,x,y;
vector <int> road[100005];
int f[100005][22],col[100005],d[100005],child[100005];
void build(int u)
{
int i,v;
for (i=0;i<road[u].size();i++)
{
v=road[u][i];
if (d[v]) continue;
d[v]=d[u]+1;f[v][0]=u;
build(v);
}
}
void dfs(int u,int fa)
{
int i,v,num=0;
if (x==0) return;
for (i=0;i<road[u].size();i++)
{
v=road[u][i];
if (v!=f[u][0]) num++;
if (col[v]||v==f[u][0]) continue;
dfs(v,u);
if (x==0) return;
}
if (num==child[u]) col[u]=1,x--,s=u;
if (u==1) return;
if (fa!=f[u][0]) dfs(f[u][0],u);
}
void del(int x)
{
int i,j=x;
for (;col[f[x][0]]!=0;)
{
for (i=1;col[f[x][i]]!=0;i++);i--;
x=f[x][i];
}
col[x]=0;
printf("%d\n",d[j]-d[x]);
s=x;
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<n;i++)
scanf("%d%d",&x,&y),road[x].push_back(y),road[y].push_back(x);
for (i=1;i<=n;i++)
sort(road[i].begin(),road[i].end());
f[1][0]=0;d[1]=1;
build(1);
for (i=1;i<=20;i++)
for (j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
//memset(col,-1,sizeof col);
for (i=2;i<=n;i++) child[f[i][0]]++;
s=1;
for (i=1;i<=m;i++)
{
if (i==1501)
{
i=1501;
}
scanf("%d%d",&y,&x);
if (y==1)
{
dfs(1,0);
printf("%d\n",s);s=f[s][0];
}
if (y==2) del(x);
}
}