• HDU 4008 Parent and son


    树形DP+LCA+思路。这题可真是有点难度......所以准备详细写一下题解。

    题意:给一颗无根树,有Q次询问,每次询问指定一个根节点X,然后让你计算Y节点的儿子和子孙中,编号最小的节点是多少。

    我们先以1为根节点进行一次树形DP,记录下每个节点的儿子和子孙中,编号最小的节点是多少。

    首先很容易想到一种情况:就是X和Y的最近公共祖先不是Y,这个时候,结果和以1为根节点建树是一模一样的,因为把X提到最上面去,不会影响到Y的子树的情况。

    剩余的情况就是X和Y的最近公共祖先等于Y(这种情况就是X在Y的子树上),这个时候,如果把X提上去,那么无法直接从以1为根节点DP的结果得出答案,我们需要进行推导。这个时候,需要分两种情况。若Y==1,这个时候把X提上去,就好比从1连出来那么多的节点的子树中,X所在子树不再是Y的后代,如果X所在子树是最小值存在的子树,那么输出次小值,否则输出最小值。若Y!=1,这个时候,也是X所在子树不成为Y的后代,那么依然需要知道X所在子树是否是最小值存在的子树,还需要知道Y的父亲的情况,因为这个时候,Y的父亲那边的所有点成为了Y的子树。

    综上所述,树形DP进行DFS的时候,我们需要记录每个子树的儿子最小值、次小值,后代最小值、次小值,每个节点的父亲节点的编号。
    还需要o(1)判断两点是否在一条链上,这个可以通过时间戳来判断。

    有了上述信息,在进行完先以1为根节点的DP之后,每一次询问,都可以在o(1)内得到答案。

    代码写的又臭又长....还是不要看了。

    #include <stdio.h>
    #include <algorithm>
    #include <string.h>
    #include <queue>
    #include <stack>
    #include <map>
    #include <vector>
    using namespace std;
    
    const int maxn=100000+10;
    const int INF=0x7fffffff;
    
    int n,m;
    vector<int>tree[maxn];
    bool vis[maxn];
    int MinSon[maxn],CiSon[maxn];
    int MinDes[maxn],CiDes[maxn];
    int belong[maxn];
    int Fa;
    int MinSonPos;
    int MinDesPos;
    int CiSonPos;
    int CiDesPos;
    struct P
    {
        int a,b;
    }pp[maxn];
    bool cmp(const P&a,const P&b) { return a.b<b.b;}
    
    int par[maxn];
    int dfnIn[maxn],dfnOut[maxn];
    int time;
    int fa[maxn],l[maxn],p[maxn][25];
     int top, sun;
     struct Edge{
         int v;
         Edge* next;
     }*adj[maxn], edge[maxn << 1];
    
     void add(int u, int v){
          Edge* p = &edge[++top];
           p -> v = v;
           p -> next = adj[u];
           adj[u] = p;
     }
     void DFS(int u, int father, int depth){
    
          fa[u] = father;  l[u] = depth;
          for(Edge* p = adj[u]; p; p = p -> next){
                int v = p -> v;
                if(v == father) continue;
    
                DFS(v, u, depth + 1);
    
          }
     }
     void init_p(int n){
          int log = 0;
          for(; (1 << log) < n; log++); log--;
          for(int i = 1; i <= n; i++){
              for(int j = 0; j <= log; j++)  p[i][j] = -1;
          }
          for(int i = 1; i <= n; i++) p[i][0] = fa[i];
          for(int j = 1; j <= log; j++){
              for(int i = 1; i <= n; i++) if(p[i][j - 1] != -1) p[i][j] = p[p[i][j - 1]][j - 1];
          }
     }
     int query(int a, int b){
         int log, i;
         if(l[a] < l[b]) swap(a, b);
         for(log = 1; (1 << log) <= l[a]; log++); log--;
         for(i = log; i >= 0; i--){
             if(l[a] - (1 << i) > l[b]){
                 a = p[a][i];
             }
         }
         sun = a;
         if(fa[a] == b) return b;
         a = fa[a];
         for(i = log; i >= 0; i--)
             if(p[a][i] != -1 && p[a][i] != p[b][i]){
                 a = p[a][i]; b = p[b][i];
             }
         return fa[a];
     }
    
    void init()
    {
        top = 0;time=0;
        for(int i = 1; i <= n; i++) adj[i] = 0;
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++) MinSon[i]=INF,MinDes[i]=INF;
        for(int i=1;i<=n;i++) CiSon[i]=INF,CiDes[i]=INF;
        for(int i=1;i<=n;i++) tree[i].clear();
    }
    
    void read()
    {
        for(int i=1; i<n; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
            tree[u].push_back(v);
            tree[v].push_back(u);
        }
    }
    
    void dfs(int now)
    {
        dfnIn[now]=++time;
        if(now!=1) belong[now]=Fa;
    
        bool fail=1;
        for(int i=0;i<tree[now].size();i++)
            if(!vis[tree[now][i]]) fail=0;
    
        if(fail)
        {
            dfnOut[now]=++time;
            return;
        }
        int *ff= new int[tree[now].size()+5];
        for(int i=0;i<tree[now].size();i++) ff[i]=0;
        for(int i=0;i<tree[now].size();i++)
        {
            if(vis[tree[now][i]]) continue;
            ff[i]=1; par[tree[now][i]]=now;
            if(now==1) Fa=tree[now][i];
            vis[tree[now][i]]=1;
            dfs(tree[now][i]);
            MinSon[now]=min(MinSon[now],tree[now][i]);
            MinDes[now]=min(MinDes[now],MinDes[tree[now][i]]);
        }
        MinDes[now]=min(MinDes[now],MinSon[now]);
    
        for(int i=0;i<tree[now].size();i++)
        {
            if(!ff[i]) continue;
            if(tree[now][i]!=MinSon[now])
                CiSon[now]=min(CiSon[now],tree[now][i]);
    
            if(MinDes[tree[now][i]]!=MinDes[now])
                CiDes[now]=min(CiDes[now],MinDes[tree[now][i]]);
    
            if(CiDes[tree[now][i]]!=MinDes[now])
                CiDes[now]=min(CiDes[now],CiDes[tree[now][i]]);
    
        }
        if(MinSon[now]!=MinDes[now])
            CiDes[now]=min(CiDes[now],MinSon[now]);
    
        dfnOut[now]=++time;
    
        delete []ff;
    }
    
    void work()
    {
        memset(vis,0,sizeof vis);
        DFS(1, -1, 0);
        init_p(n);
        vis[1]=1;dfs(1);
        
        MinSonPos=INF; MinDesPos=INF;
        CiSonPos=INF; CiDesPos=INF;
    
        for(int i=0;i<tree[1].size();i++)
            MinSonPos=min(MinSonPos,tree[1][i]);
    
        for(int i=0;i<tree[1].size();i++)
        {
            if(tree[1][i]==MinSonPos) continue;
            CiSonPos=min(CiSonPos,tree[1][i]);
        }
    
        int yy=0;
        for(int i=0;i<tree[1].size();i++)
        {
            pp[yy].a=tree[1][i];
            pp[yy++].b=min(tree[1][i],MinDes[tree[1][i]]);
        }
        sort(pp,pp+yy,cmp);
        MinDesPos=pp[0].a;
        if(yy>=1) CiDesPos=pp[1].a;
    
    
        for(int i=1;i<=m;i++)
        {
            int X,Y;
            scanf("%d%d",&X,&Y);
            int U=query(X,Y);
    
            if(U!=Y)
            {
                if(MinDes[Y]==INF) printf("no answers!
    ");
                else printf("%d %d
    ",MinSon[Y],MinDes[Y]);
            }
    
            else
            {
                if(Y==1)
                {
                    int ans1,ans2;
                    int be=belong[X];
                    if(MinSonPos==be) ans1=CiSonPos;
                    else ans1=MinSonPos;
                    if(MinDesPos==be) ans2=CiDesPos;
                    else ans2=MinDesPos;
                    if(ans1==INF||ans2==INF) printf("no answers!
    ");
                    else printf("%d %d
    ",ans1,min(ans2,MinDes[ans2]));
                }
                else
                {
                    int ans=INF;
                    if(dfnIn[X]>=dfnIn[MinSon[Y]]&&dfnOut[X]<=dfnOut[MinSon[Y]]) ans=min(CiSon[Y],par[Y]);
                    else if(dfnIn[MinSon[Y]]>=dfnIn[X]&&dfnOut[MinSon[Y]]<=dfnOut[X]) ans=min(CiSon[Y],par[Y]);
                    else ans=min(MinSon[Y],par[Y]);
                    printf("%d 1
    ",ans);
                }
            }
        }
    }
    
    int main()
    {
        int T;
    
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            init();
            read();
            work();
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    C#中的多态
    反编译工具
    富文本粘贴图片
    [Silverlight入门系列]用TransformToVisual和Transform取得元素绝对位置(Location)
    Silverlight在IIS中的配置
    HubbleDotNet开源全文搜索数据库项目技术详解
    Thank you for choosing Telerik RadRichTextBox
    Asp.net读取AD域信息的方法<转>
    Sharepoint学习笔记—ECMAScript对象模型系列1、ECMAScript对象模型的引入
    SharePoint WebService
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5187261.html
Copyright © 2020-2023  润新知