给一棵树,每次每次询问一个点是否是另一个点的祖先?
输入时是每个下标对应节点的儿子的数量
用dfs序 时间戳。。
如果一个点是另一个点的祖先,那么它的两个标记一定在祖先的范围之内
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <cmath> #define rap(a, n) for(int i=a; i<=n; i++) #define MOD 2018 #define LL long long #define ULL unsigned long long #define Pair pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define _ ios_base::sync_with_stdio(0),cin.tie(0) //freopen("1.txt", "r", stdin); using namespace std; const int maxn = 20022000, INF = 0x7fffffff; int r[maxn], l[maxn], sum[333333], zstack[maxn]; bool vis[maxn]; int dfs_clock, top, k, n, m, x, y; void dfs() { mem(vis, 0); dfs_clock = zstack[top=1] = 0; while(top > 0) { k = zstack[top]; //stack里存了结点 赋值给k后 k及对应了输入时的下标 即如果k<n 可以判定是否在输入的时候说了它有几个儿子 if(!vis[k]) { vis[k] = 1, l[k] = ++dfs_clock; if(k < n) for(int i=k==0?1:sum[k-1]+1; i<=sum[k]; i++) zstack[++top] = i; } else r[k] = ++dfs_clock, top--; } } int main() { int T, kase = 0; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i=0; i<n; i++) { int tmp; scanf("%d", &tmp); sum[i]=i==0?tmp:sum[i-1] + tmp; //每个下标对应的前缀和 即为当前节点的最后一个儿子的值 } dfs(); printf("Case %d: ", ++kase); scanf("%d",&m); while (m--){ scanf("%d%d",&x,&y); if (l[x]<l[y] && r[x]>r[y]) puts("Yes"); else puts("No"); } if(T) cout<<endl; } return 0; }