Description
给出一棵n个节点以1为根的树,和m次操作。
每次操作把x个人扔进这棵树。
每个人会选择当前节点中一个没有人且编号最大的节点走过去。
问最后一个人停在哪个节点。
或者把x这个节点的人删除,把它上面的所有人往下移一格,问移动了多少人。
n,m<=10^5
Solution
你有木有觉得这个走的方法很像dfs序的遍历?
那么我们可以构造出这个特殊的dfs序,不过每次我们选择编号大的先走。
这东西你可以用set/vector/map/queue等等黑科技来做。
(p党伤不起就去转c吧)
这样子就可以保证这个序列从后往前就是我们要插入的顺序了。
于是我们可以给每个点一个优先级,然后把它们按优先级排序。
同时要兹瓷插入删除。。
辣么用set/queue/heap就好辣
p党:卒
操作二就倍增往上跳到最上面一个有人的节点。
因为不可能一个节点没人但他的父辈有人。
然后就解决啦(黑科技大全纪念)
Code
#include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 100005
using namespace std;
typedef set<int> :: iterator its;
set<int> s[N];
int dfn[N],fa[N][17],d[N],tot,n,m,x,y,z;
bool bz[N],in[N];
struct note{
int id;
friend bool operator < (note x,note y) {
return dfn[x.id]<dfn[y.id];
}
};
typedef set<note> :: iterator itn;
set<note> q;
void dfs(int x,int y) {
dfn[x]=++tot;fa[x][0]=y;d[x]=d[y]+1;
its it=s[x].end();bool pd=0;
do {
it--;
if (*it!=y) pd=1,dfs(*it,x);
} while (it!=s[x].begin());
note z;z.id=x;
if (!pd) q.insert(z),in[x]=1;
}
int jump(int x) {
fd(j,16,0) if (bz[fa[x][j]]) x=fa[x][j];
return x;
}
int main() {
scanf("%d%d",&n,&m);
fo(i,1,n-1) scanf("%d%d",&x,&y),s[x].insert(y),s[y].insert(x);
dfs(1,0);
fo(j,1,16) fo(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];
for(;m;m--) {
scanf("%d%d",&z,&x);
if (z==1) {
fo(i,1,x) {
itn it=q.end();it--;
note v=*it;bz[v.id]=1;
q.erase(it);
if (!in[fa[v.id][0]]) {
in[fa[v.id][0]]=1;
note z;z.id=fa[v.id][0];
q.insert(z);
}
if (i==x) printf("%d\n",v.id);
}
} else {
int v=jump(x);
printf("%d\n",d[x]-d[v]);
note z;z.id=v;
q.insert(z);
in[v]=1;bz[v]=0;
}
}
}