zoukankan      html  css  js  c++  java
  • 【栈模拟dfs】Cells UVALive

    题目链接:https://cn.vjudge.net/contest/209473#problem/D

    题目大意:有一棵树,这棵树的前n个节点拥有子节点,告诉你n的大小,以及这n个节点各有的子节点个数,对于Q个询问<x,y>,回答x是否是y的祖先。

    解题思路:

    一开始想的LCA,倍增解决。然后一看数据范围,2e7!瞬间被吓回来了。

    想了各种方法百思不得其解最后看了题解orz(强烈建议独立思考,挫败感很强!)。

    题解……万分机智,我们思考一下深搜建树的过程,先遍历到一个父亲节点,再往下遍历到这个父亲节点的子节点,再往上回溯到该父亲节点。我们发现如果A是B的祖先,A的遍历时间点早于B的遍历时间点早于B的回溯时间点早于A的回溯时间点。

    也就是说我们如果给每个点建立两个时间值(类似Tarjan的思想,预计后天讲Tarjan),第一个时间值是遍历时间点,第二个时间值是回溯时间点,建树的时候预处理出来,那么对于每个询问,就可以O(1)得出结果了(判断一下四个值大小关系)。

    这样乍一听好像很好实现,然而此题还有一个trick,就是什么样的电脑才能深搜递归2e7层?果断会爆栈!

    最后这道题的难点(?)转化成了手动扩栈模拟dfs,很简单的样子,就不赘述了。

    坑点:注意数组大小,容易RE(别开太大了,稍微大一点就好)。

    下面放965msAC代码:

     1 /* by Lstg */
     2 /* 2018-03-05 21:02:03 */
     3 
     4 #include<stdio.h>
     5 #include<iostream>
     6 #include<queue>
     7 #define MAXN 20000005
     8 using namespace std;
     9 
    10 int dfn[MAXN],dfm[MAXN],stk[MAXN],n;
    11 queue<int>g[300005];//这里太大就会RE
    12 
    13 void _mydfs(int x){
    14     
    15     int top=0,num=1,y;
    16     dfn[x]=num++;
    17     stk[++top]=x;
    18     while(top){
    19         x=stk[top];
    20         if(x>n||g[x].empty()){/*先判断x的大小防RE和WA(有时溢出不会告诉你是RE,而会返回WA)*/
    21             dfm[x]=num++;
    22             top--;
    23         }
    24         else{
    25             y=g[x].front();
    26             g[x].pop();
    27             dfn[y]=num++;
    28             stk[++top]=y;
    29         }
    30     }
    31 }
    32 
    33 int main(){
    34 
    35     int T,tot,i,x,y;
    36     scanf("%d",&T);
    37     for(int cc=1;cc<=T;cc++){
    38         scanf("%d",&n);
    39         tot=0;
    40         
    41         for(i=0;i<n;i++){
    42             while(!g[i].empty())g[i].pop();
    43             scanf("%d",&x);
    44             while(x--)
    45                 g[i].push(++tot);
    46         }
    47         _mydfs(0);
    48         printf("Case %d:
    ",cc);
    49         scanf("%d",&n);
    50         for(i=1;i<=n;i++){
    51             scanf("%d%d",&x,&y);
    52             if(dfn[x]<dfn[y]&&dfm[x]>dfm[y])
    53                 puts("Yes");
    54             else puts("No");
    55         }
    56         if(cc!=T)putchar(10);
    57     }
    58     return 0;
    59 }
  • 相关阅读:
    Leetcode 50.Pow(x,n) By Python
    Leetcode 347.前K个高频元素 By Python
    Leetcode 414.Fizz Buzz By Python
    Leetcode 237.删除链表中的节点 By Python
    Leetcode 20.有效的括号 By Python
    Leetcode 70.爬楼梯 By Python
    Leetcode 190.颠倒二进制位 By Python
    团体程序设计天梯赛 L1-034. 点赞
    Wannafly挑战赛9 C-列一列
    TZOJ Start
  • 原文地址:https://www.cnblogs.com/L-Excalibur/p/8511527.html
Copyright © 2011-2022 走看看