把询问离线之后就能随便搞了, 去check一下是不是祖先, 可以用倍增也能用dfs序。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; int n, m, cnt, deg[N], fa[N], op[N], x[N], y[N], depth[N], f[N][20]; bool vis[N]; bool ans[N]; vector<int> G[N]; vector<int> qus[N]; int getRoot(int x) { return x == fa[x] ? x : fa[x] = getRoot(fa[x]); } void Merge(int x, int y) { fa[getRoot(x)] = getRoot(y); } void dfs(int u, int fa, int idx) { vis[u] = idx; depth[u] = depth[fa] + 1; f[u][0] = fa; for(int i = 1; i < 20; i++) f[u][i] = f[f[u][i - 1]][i - 1]; for(int& v : G[u]) if(!vis[v]) dfs(v, u, idx); } bool check(int u, int v) { if(depth[u] < depth[v]) return false; if(vis[u] != vis[v]) return false; if(getRoot(u) != getRoot(v)) return false; for(int i = 19; i >= 0; i--) if(depth[f[u][i]] >= depth[v]) u = f[u][i]; return u == v; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= m; i++) { scanf("%d%d", &op[i], &x[i]); if(op[i] != 2) scanf("%d", &y[i]); if(op[i] == 3) qus[y[i]].push_back(i); if(op[i] == 1) G[y[i]].push_back(x[i]), deg[x[i]]++; } for(int i = 1; i <= n; i++) if(!deg[i]) dfs(i, 0, ++cnt); cnt = 0; for(int i = 1; i <= m; i++) { if(op[i] == 1) { Merge(x[i], y[i]); } else if(op[i] == 2) { cnt++; for(auto& p : qus[cnt]) if(check(x[i], x[p])) ans[p] = true; } } for(int i = 1; i <= m; i++) if(op[i] == 3) printf("%s ", ans[i] ? "YES" : "NO"); return 0; } /**/