CCO2021 Through Another Maze Darkly
不需要任何 log 数据结构的做法。
首先考虑一个暴力结论:我们走有限次之后(实际上是
注意,在这个欧拉游走序中,我们每个节点的儿子顺序,应该是在原出边顺序中,从父节点之后的那个儿子开始,父节点之前的那个儿子结束,形成的一个顺序。
我们把其最终结果的欧拉游走序给求出来。如果我们在某一时刻”解决“了一个树上节点,那么在之后的时刻,遇到这个点就直接按照欧拉游走序上的往后走就行了。所以对于欧拉序上的每一个位置,我们可以打一个标记。而当我们对于
我们假设我们现在在欧拉序的没有标记的
所以我们的操作就是:对于
复杂度正确,因为我们每次遍历到标记节点就会删除一些标记,而两次标记访问之间最多有一次非标记访问。
要对问询排序所以得勉为其难地带个 log。
复杂度
Update:"你可以基排的",所以可以直接做到
const int N=1.6e6+9;
int n,Q,nxt[N],fa[N],dfn[N],tick,deg[N],tot,hd[N],lst[N],fst[N],ans[N],tag[N];
pii q[N];
vi pos[N],t[N];
struct edge {int to,nxt;} e[N];
int find(int x) {return nxt[x]==x?x:nxt[x]=find(nxt[x]);}
int dis(int x,int y) {
if(x<y) return y-x;
else return tick-x+y;
}
void del(int x) {nxt[x]=find(x%tick+1); tag[x]=0;}
void dfs1(int u) {for(int v:t[u]) if(v!=fa[u]) fa[v]=u, dfs1(v);}
int calc(int x,int y) {
x+=y, x%=tick; if(x==0) x=tick;
return dfn[x];
}
void dfs2(int u) {
dfn[++tick]=u; pos[u].eb(tick); fst[u]=tick;
for(int i=hd[u];i;i=e[i].nxt) {
dfs2(e[i].to);
dfn[++tick]=u; pos[u].eb(tick);
}
}
void work(int p,int time,int qt) {
int u=dfn[p];
if(tag[p]) {
for(int x:pos[u]) del(x);
while(qt<=Q&&q[qt].fi==time) ans[q[qt].se]=u, qt++;
if(t[u].size()==1) work(t[u][0],time+1,qt);
else work(t[u][1],time+1,qt);
} else {
int np=find(p);
if(!tag[np]) {
while(qt<=Q) ans[q[qt].se]=calc(p,q[qt].fi-time), qt++;
return;
}
int nt=time+dis(p,np);
while(qt<=Q&&q[qt].fi<nt) ans[q[qt].se]=calc(p,q[qt].fi-time), qt++;
work(np,nt,qt);
}
}
signed main() {
n=read(), Q=read();
rep(i,1,n) {
deg[i]=read();
rep(j,1,deg[i]) t[i].eb(read());
}
dfs1(1);
rep(i,1,n) {
int pos=0;
if(i!=1) {while(t[i][pos]!=fa[i]) pos++;}
pos=(pos+1)%deg[i], hd[i]=tot+1;
rep(j,1,deg[i]) {
if(t[i][pos]==fa[i]) break;
e[++tot]=(edge){t[i][pos],tot+1};
pos=(pos+1)%deg[i];
}
if(hd[i]>tot) hd[i]=0;
else e[tot].nxt=0;
}
dfs2(1); tick--;
per(i,tick,1) {
int u=dfn[i]; lst[u]=i;
if(fst[u]==i) {
for(int &x:t[u]) {
if(!lst[x]) x=fst[x];
else x=lst[x];
}
}
}
rep(i,1,Q) q[i].fi=read(), q[i].se=i;
sort(q+1,q+Q+1);
rep(i,1,tick) nxt[i]=i, tag[i]=1;
work(1,0,1);
rep(i,1,Q) printf("%lld\n",ans[i]);
return 0;
}