题目大意:
自己去看。。。
Solution:
直接离线进行处理,首先构建出完整的树,处理出dfs序。对于每个询问,事实上是问一个点是否在一条路径上,究竟是哪条路径可以利用并查集维护。
那么我们就需要知道一个点u是否是另一个点v的祖先。
事实上,这等价于:in[u]<=in[v]&&out[u]>=out[v].
于是总的时间复杂度为O(n\alpha(n)).
Code:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cctype>
using namespace std;
inline int getc() {
static const int L = 1 << 15;
static char buf[L], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, L, stdin);
if (S == T)
return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()));
int tmp = c - '0';
while(isdigit(c = getc()))
tmp = (tmp << 1) + (tmp << 3) + c - '0';
return tmp;
}
#define N 100010
int head[N], next[N], end[N];
void addedge(int a, int b) {
static int q = 1;
end[q] = b;
next[q] = head[a];
head[a] = q++;
}
int root[N], size[N];
int find(int x) {
return x == root[x] ? x : root[x] = find(root[x]);
}
int down[N], up[N];
struct Ask {
int ins, lab;
Ask(int _ins = 0, int _lab = 0):ins(_ins),lab(_lab){}
}S[N];
int num;
int in[N], out[N], tclock;
bool vis[N];
void dfs(int x) {
vis[x] = 1;
in[x] = ++tclock;
for(int j = head[x]; j; j = next[j])
dfs(end[j]);
out[x] = tclock;
}
inline bool inanc(int Son, int Anc) {
return in[Anc] <= in[Son] && out[Anc] >= out[Son];
}
int main() {
int n, m;
n = getint();
m = getint();
register int i;
for(i = 1; i <= n; ++i)
root[i] = i, size[i] = 1;
int sign, now = 0, a, b, x;
for(i = 1; i <= m; ++i) {
sign = getint();
if (sign == 1) {
a = getint(), b = getint();
addedge(b, a);
vis[a] = 1;
root[a] = b;
}
if (sign == 2) {
a = getint();
down[++now] = a;
up[now] = find(a);
}
if (sign == 3) {
a = getint(), x = getint();
S[++num] = Ask(a, x);
}
}
for(i = 1; i <= n; ++i)
if (!vis[i])
dfs(i);
for(i = 1; i <= num; ++i) {
if (inanc(down[S[i].lab], S[i].ins) && inanc(S[i].ins, up[S[i].lab]))
puts("YES");
else
puts("NO");
}
return 0;
}