链接
题意
给出一个n个节点的树(n <= 20000000),和m个询问,每个询问给出a、b,问a是否是b的祖先。
题解
跑一遍dfs序,记录每个节点子树的域,如果b是a的后代,则st[a] < st[b] && nd[a] >= st[b],注意输入给的有相同的节点,是个坑点,这种情况是No。
另外,直接跑递归是会爆栈的(注意n的规模),应用循环写dfs。
代码
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
#define maxn (20000010)
int st[maxn], nd[maxn];
vector<int> son[maxn];
queue<int> que;
void getg()
{
while(!que.empty()) que.pop();
int n, tot = 0;
cin >> n;
que.push(0);
son[0].clear();
for(int i = 0, a, u = 0; i < n; i++)
{
scanf("%d", &a);
u = que.front(); que.pop();
while(a--)
{
son[u].push_back(++tot);
que.push(tot);
son[tot].clear();
}
}
}
int cnt;
stack<int> sta;
void dfs(int u)
{
cnt = 0;
sta.push(u);
st[u] = 0;
while(!sta.empty())
{
int x = sta.top();
if(st[x] != 0)
{
nd[x] = cnt;
sta.pop();
continue;
}
st[x] = ++cnt;
for(int i = 0; i < son[x].size(); i++)
{
sta.push(son[x][i]);
st[son[x][i]] = 0;
}
}
/*
st[S[top = 1] = u] = 0;
while(top > 0)
{
int x = S[top];
if(st[x] != 0)
{
nd[x] = cnt;
top--;
continue;
}
st[x] = ++cnt;
for(int i = 0; i < son[x].size(); i++)
{
st[son[x][i]] = 0;
S[++top] = son[x][i];
}
}
*/
}
int main()
{
int T, kase = 0;
cin >> T;
while(T--)
{
getg();
dfs(0);
int m, a, b;
cin >> m;
printf("Case %d:\n", ++kase);
while(m--)
{
scanf("%d%d", &a, &b);
if(st[b] > st[a] && st[b] <= nd[a])
printf("Yes\n");
else
printf("No\n");
}
if(T) printf("\n");
}
return 0;
}