【题解】[CCO2021] Through Another Maze Darkly
nb的树上思维DS题。
如果我们把每个指针的的指向集合作为状态,由于状态集合是有限的,并且相同的初始状态则结束位置相同,所以最后一定会循环。但是并不一定是纯循环。
由于这是一颗树,所以我们考虑特殊性质。如果是一个菊花图,显然就是一个排列不断循环。如果是链,手算一下发现就是从点 \(1\) 开始,不断来回向两边扩展。每次扩展多少取决于指针的指向。
所以我们定义 \(f_i\) 表示节点 \(i\) 的重标号,按一下方式标号。
对于当前点 \(i\) ,它父亲前面出现的子节点标号为它的标号,后面出现的标号要\(+1\)。
然后我们再求整个树的 DFS 序,注意 DFS 序是唯一的,每次我们从父节点顺时针的下一个子节点开始。
这样标号,我们就构造出了整个路径。我们按以下方式还原路径。
定义 \(s_i\) 表示标号 \(\le i\) 的点在 DFS 序中出现的位置连起来,那么原路径就是 \(s_1s_2\cdots\)。
所以从 \(s_n\) 开始就一直以 \(s_n\) 循环,对于前面的可以直接可持久化线段树维护 \(s_i\),二分后再在线段树上二分可以做到时空复杂度 \(\mathcal{O}(N\log N)\)。事实上可以对询问离线,可以将空间优化到线性,但是本题有一个G所以无所谓。
/*
Author : SharpnessV
Right Output ! & Accepted !
*/
#include<bits/stdc++.h>
//#define int long long
#define rep(i, a, b) for(int i = (a);i <= (b);i++)
#define pre(i, a, b) for(int i = (a);i >= (b);i--)
#define rp(i, a) for(int i = 1; i <= (a); i++)
#define pr(i, a) for(int i = (a); i >= 1; i--)
#define go(i, x) for(auto i : x)
#define mp make_pair
#define pb push_back
#define pf push_front
#define fi first
#define se second
#define ze(p) memset(p, 0, sizeof(p))
#define mem(p, x) memset(p, x, sizeof(p))
#define YES puts("YES")
#define NO puts("NO")
#define Yes puts("Yes")
#define No puts("No")
#define si(x) (int)(x).size()
#define db cerr
#define pc putchar
#define gc getchar
#define el putchar('\n')
using namespace std;
const double eps = 1e-15, pi = 3.1415926535897932385;
typedef long long LL;
typedef pair<int,int> Pr;
const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}, inf = 0x7fffffff;
//Author : SharpnessV
//#define main Solution
char buf[1<<22],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read(){
int x = 0;bool f = 1;char ch = gc();
while(!isdigit(ch))f = ('-' == ch ? 0 : 1), ch = gc();
while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
if(f)return x;return -x;
}
inline LL Read(){
LL x = 0;bool f = 1;char ch = gc();
while(!isdigit(ch))f = ('-' == ch ? 0 : 1), ch = gc();
while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
if(f)return x;return -x;
}
int gcd(int x,int y){return y ? gcd(y, x % y) : x;}
int lcm(int x,int y){return x / gcd(x, y) * y;}
#define P 1000000007
//#define P 998244353
#define bas 229
inline void ad(int &x, int y){x += y; if(x >= P) x -= P;}
inline void su(int &x, int y){x -= y; if(x < 0) x += P;}
inline void cmn(int &x,int y){if(y < x) x = y;}
inline void cmx(int &x,int y){if(y > x) x = y;}
inline void cmn(LL &x, LL y){if(y < x) x = y;}
inline void cmx(LL &x, LL y){if(y > x) x = y;}
int Pow(int x, int y){
if(y < 0)return Pow(Pow(x, P - 2), -y);
int now = 1 ;
for(;y;y >>= 1, x = 1LL * x * x % P)if(y & 1) now = 1LL * now * x % P;
return now;
}
/*******************************************************************************************************************/
/* */
/*******************************************************************************************************************/
#define N 800005
#define M 40000005
int n, q, deg[N], u[N << 1], d[N], idx, m;LL s[N];
vector<int>e[N], c[N << 1];
void dfs(int x,int fa){
if(x != 1)u[++idx] = x, c[d[x]].pb(idx), cmx(m, d[x]);
bool flag = 0;
go(y, e[x]){
if(y == fa)flag = 1;
else if(flag)d[y] = d[x] + 1, dfs(y, x), u[++idx] = x, c[d[y]].pb(idx);
}
go(y, e[x]){
if(y == fa)break;
d[y] = d[x], dfs(y, x), u[++idx] = x, c[d[y]].pb(idx);
}
}
struct Node{
int l, r, val;
}a[M];
#define ls a[x].l
#define rs a[x].r
#define S a[x].val
int tot, rt[N];
void ins(int &x,int l,int r,int pos){
int y = x; x = ++tot, a[x] = a[y];
if(l == r)S = 1;
else{
int mid = (l + r) >> 1;
if(mid >= pos)ins(ls, l, mid, pos);
else ins(rs, mid + 1, r, pos);
S = a[ls].val + a[rs].val;
}
}
void ask(int x,int l,int r,int k){
if(l == r)printf("%d\n", u[l]);
else{
int mid = (l + r) >> 1;
if(a[ls].val >= k)ask(ls, l, mid, k);
else ask(rs, mid + 1, r, k - a[ls].val);
}
}
int main(){
//freopen("d1p3.4-42.in","r",stdin);
//freopen("OUTPUT","w",stdout);
//int T = read();while(T--)solve();
n = read(), q = read();
rp(i, n){
deg[i] = read();int x = read();
rp(j, deg[i] - 1)e[i].pb(read());
e[i].pb(x);
}
d[1] = 1, dfs(1, 0);
rt[0] = ++tot;
rp(i, m){
rt[i] = rt[i - 1];
go(y, c[i])ins(rt[i], 1, idx, y);
s[i] = s[i - 1] + si(c[i]);
}
rp(i, m)s[i] += s[i - 1];
//rp(i, idx)printf("%d ",u[i]);el;
//rp(i, idx)printf("%d ",w[i]);el;
//rp(i, n)printf("%d ",d[i]);el;
while(q--){
LL x = Read();
if(x > s[m]){
x = (x - s[m - 1]) % (s[m] - s[m - 1]);
if(!x)x = s[m] - s[m - 1];
ask(rt[m], 1, idx, x);
}
else{
int l = 1, r = m, ed = 0;
while(l <= r){
int mid = (l + r) >> 1;
if(s[mid - 1] < x)ed = mid, l = mid + 1;
else r = mid - 1;
}
x -= s[ed - 1];
ask(rt[ed], 1, idx, x);
}
}
return 0;
}