考虑一颗普通的树,DFS一遍后得到每个点的DFS前序历遍顺序值dfsid[] ,和以改点为根的子树的总结点数num[]。
(比如第一组样例dfsid[]={0,1,6,8,2,3,7,9,4,5} num[]={10,5,2,2,1,3,1,1,1,1});
那么要判断a是否为b的祖先,只要满足dfsid[a]<dfsid[b]<dfsid[a]+num[a]
因为这题的结点最多会有2000W,所以不能建完整的树,只能建n个结点,否则超时。
由于编号大于n的结点肯定是叶节点,我们可以通过求son数组(每个结点的儿子数)的前缀和,然后二分查找找到b的父亲结点,再判断。
大概步骤就是
1.BFS建树,只建n个结点。
2.DFS,求dfsid[] 和num[] 数据量大,用栈模拟递归
3.求son[]的前缀和
4.判断每对a,b. 会有a==b的数据
总复杂度O(mlogn)
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<sstream> #include<cmath> #include<climits> #include<string> #include<map> #include<queue> #include<vector> #include<stack> #include<set> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; #define pb(a) push(a) #define INF 0x1f1f1f1f #define lson idx<<1,l,mid #define rson idx<<1|1,mid+1,r #define PI 3.1415926535898 template<class T> T min(const T& a,const T& b,const T& c) { return min(min(a,b),min(a,c)); } template<class T> T max(const T& a,const T& b,const T& c) { return max(max(a,b),max(a,c)); } void debug() { #ifdef ONLINE_JUDGE #else freopen("d:\in1.txt","r",stdin); freopen("d:\out1.txt","w",stdout); #endif } int getch() { int ch; while((ch=getchar())!=EOF) { if(ch!=' '&&ch!=' ')return ch; } return EOF; } const int maxn=300200; vector<int> g[maxn]; int n; int son[maxn]; int dfsid[maxn]; int num[maxn]; struct stacknode { int u,i; }; int dfs() { int dfs_clock=0; stack<stacknode> st; st.push((stacknode){0,0}); while(!st.empty()) { stacknode x=st.top();st.pop(); if(x.i==0){num[x.u]=1;dfsid[x.u]=dfs_clock++;} if(x.i<g[x.u].size()) { x.i++; st.push(x); st.push((stacknode){g[x.u][x.i-1],0}); }else { for(int i=0;i<g[x.u].size();i++) num[x.u]+=num[g[x.u][i]]; } } } void build() { int num=1; queue<int> q; q.push(0); while(!q.empty()) { int x=q.front();q.pop(); g[x].clear(); if(x==n-1)return ; if(num>=n)continue; for(int i=1;i<=son[x];i++) { g[x].push_back(num); q.push(num++); if(num>=n)break; } } } int main() { int t; scanf("%d",&t); for(int ca=1;ca<=t;ca++) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&son[i]); build(); dfs(); for(int i=1;i<n;i++) son[i]+=son[i-1]; int m; scanf("%d",&m); printf("Case %d: ",ca); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); if(a==b) { printf("No ");continue; } if(b>=n) b=lower_bound(son,son+n,b)-son; if(a<n&&dfsid[a]+num[a]>dfsid[b]&&dfsid[b]>=dfsid[a]) printf("Yes "); else printf("No "); } if(ca!=t)printf(" "); } return 0; }