题解:P11315 [RMI 2021] 速通 / Speedrun
题目传送门
题目分析
题目要求在有
思路
首先观察数据的大小和限制,最坏情况下每个节点只能存大小为
接下来思考
对于树的遍历存在众所周知的两种遍历方法:
方法
在第一次运行里,根据边建好图后跑一个
在第二次运行里,我们先不断地走到当前节点的父亲,到达根节点,然后不断尝试走到
这样子走失误次数最多就是总节点数减去一定不会走失误的两个节点即根节点与
代码
#include<bits/stdc++.h>
#define bit bitset<10>
using namespace std;
const int N=1e3+5;
void setHintLen(int);void setHint(int,int, bool);int getLength();bool getHint(int);bool goTo(int);
int dfn[N],idx,f[N],rdfn[N];
vector<int> a[N];
void dfs(int now,int fa){
f[now]=fa;
dfn[now]=++idx;
rdfn[idx]=now;
for(const int& i:a[now]){
if(i==fa) continue;
dfs(i,now);
}
}//dfs序
void assignHints(int subtask, int n, int A[], int B[]){
setHintLen(20);
for(int i=1;i<n;i++){
a[A[i]].push_back(B[i]);
a[B[i]].push_back(A[i]);
}
dfs(1,0);
for(int i=1;i<=n;i++){
bit z=f[i];
for(int j=1;j<=10;j++)
setHint(i,j,z[j-1]);//存父亲
if(dfn[i]<n){
bit nz=rdfn[dfn[i]+1];
for(int j=1;j<=10;j++)
setHint(i,j+10,nz[j-1]);//存dfn为下一个的节点
}
}
}
void speedrun(int subtask, int n, int start){
bit sz;
for(int i=1;i<=10;i++)
sz[i-1]=getHint(i);
int fa=sz.to_ulong();
while(fa>0){
goTo(fa);
bit nz;
for(int i=1;i<=10;i++)
nz[i-1]=getHint(i);
fa=nz.to_ulong();
}//走到根节点
for(int i=1;i<=10;i++)
sz[i-1]=getHint(i+10);
int nxt=sz.to_ulong();
while(nxt>0){
bool flag=goTo(nxt);
if(flag){
bit nz;
for(int i=1;i<=10;i++)
nz[i-1]=getHint(i+10);
nxt=nz.to_ulong();
}//走到了继续走
else{
bit nz;
for(int i=1;i<=10;i++)
nz[i-1]=getHint(i);
goTo(nz.to_ulong());
}//走不到就回到其父亲节点
}
}