• 经典问题之树的深度


    给定一棵树,求出分别以每个点为根的树的深度。

    其实这道题是四五月份时宁波初中比赛时的题目,当时的数据范围自然是1000,然后O(n^2)水过。当时比赛时题做完了,闲的无聊,打算想一想O(n)做法,当时也感觉挺可做的。几个月后突然想起来,今天就写了一下。算是一道树形dp吧。

    这题描述简单,做法也算有趣,自己感觉是个有意思的问题。

    解答也一句话,意会即可:

    每个点的深度=MAX(每个点向下的最长路,每个点向上的最长路);

    每个点向下的最长路=MAX(子树的向下的最长路)+1;

    每个点向上的最长路=MAX(父亲向上的最长路+1,父亲向下的次长路+1)【当这个点是父亲最大的儿子时】,

                                      父亲的深度+1【当这个点不是父亲最大的儿子时】。

    我们还可以有一些好的拓展。

    请看下面一道题

    树的合并(connect.pas/c/cpp)
    给定两棵树,则总共有N*M 种方案把这两棵树通过加一条边连成一棵树,求这N*M 棵
    树的直径大小之和。
    N<=10^5,M<=10^5

    可以用预处理+排序+扫描的方法在O(NlogN)时间内解决。具体见Code。

    connect
      1 /*
      2     Problem:
      3     Algorithm:
      4     Note:
      5 */
      6 #include<cstdio>
      7 #include<cstring>
      8 #include<algorithm>
      9 #include<set>
     10 #include<vector>
     11 #include<map>
     12 #include<string>
     13 #include<iomanip>
     14 #include<iostream>
     15 #include<cmath>
     16 #include<queue>
     17 using namespace std;
     18 
     19 #define rep(i,x,y) for(i=x;i<=y;i++)
     20 #define _rep(i,x,y) for(i=x;i>=y;i--)
     21 #define CL(S,x) memset(S,x,sizeof(S))
     22 #define CP(S1,S2) memcpy(S1,S2,sizeof(S2))
     23 #define mp make_pair
     24 //#define x first
     25 //#define y second
     26 #define MAX(x,y) ((x)>(y)?(x):(y))
     27 //#define MIN(x,y) ((x)<(y)?(x):(y))
     28 #define sqr(x) ((x)*(x))
     29 
     30 typedef long long int64;
     31 typedef long double real;
     32 
     33 const int MAXN=200010;
     34 int N[2],i,j,best;int64 ans0;
     35 int st[2][MAXN],q[MAXN],fa[MAXN];
     36 int ans[MAXN],dep[MAXN],up[MAXN],maxson0[MAXN],maxson1[MAXN];
     37 int64 sum[MAXN];
     38 
     39 struct E
     40 {
     41     int edge,e[MAXN],b[MAXN],first[MAXN],last[MAXN];
     42     void clear(){CL(first,-1);CL(b,-1);}
     43     void add(int x,int y)
     44     {
     45         e[edge]=y;
     46         if(first[x]==-1)first[x]=edge;
     47         else b[last[x]]=edge;
     48         last[x]=edge++;
     49     }
     50 }g[2];
     51 
     52 int bfs(int start,int t)
     53 {
     54     int i,j,k;
     55     q[1]=start;CL(fa,0);
     56     for(i=j=1;i<=j;i++)
     57     for(k=g[t].first[q[i]];k>=0;k=g[t].b[k])
     58     if(g[t].e[k]!=fa[q[i]]){fa[g[t].e[k]]=q[i];q[++j]=g[t].e[k];}
     59     return q[j];
     60 }
     61 void work(int t)
     62 {
     63     int i,j,k,n=N[t];
     64     bfs(1,t);CL(dep,0);CL(maxson0,0);CL(maxson1,0);
     65     ans[0]=dep[0]=-1;
     66     _rep(i,n,1)
     67     {
     68         for(k=g[t].first[q[i]];k>=0;k=g[t].b[k])
     69         if(g[t].e[k]!=fa[q[i]])
     70         if(dep[g[t].e[k]]>dep[maxson0[q[i]]])maxson1[q[i]]=maxson0[q[i]],maxson0[q[i]]=g[t].e[k];
     71         else if(dep[g[t].e[k]]>dep[maxson1[q[i]]])maxson1[q[i]]=g[t].e[k];
     72         dep[q[i]]=dep[maxson0[q[i]]]+1;
     73     }
     74 
     75     rep(i,1,n)
     76     {
     77         if(q[i]!=maxson0[fa[q[i]]])up[q[i]]=ans[fa[q[i]]]+1;
     78         else up[q[i]]=MAX(up[fa[q[i]]]+1,dep[maxson1[fa[q[i]]]]+2);
     79         ans[q[i]]=MAX(up[q[i]],dep[q[i]]);
     80     }
     81     
     82     st[t][0]=n;
     83     rep(i,1,n)st[t][i]=ans[i];
     84     
     85 }
     86 
     87 int main()
     88 {
     89     freopen("connect.in","r",stdin);
     90     freopen("connect.out","w",stdout);
     91     scanf("%d%d",&N[0],&N[1]);
     92     g[0].clear();g[1].clear();
     93     int x,y;
     94     rep(i,1,N[0]-1)scanf("%d%d",&x,&y),g[0].add(x,y),g[0].add(y,x);
     95     rep(i,1,N[1]-1)scanf("%d%d",&x,&y),g[1].add(x,y),g[1].add(y,x);
     96     
     97 
     98     work(0);work(1);
     99     
    100     
    101     sort(st[0]+1,st[0]+1+st[0][0]);
    102     sort(st[1]+1,st[1]+1+st[1][0]);
    103     
    104     best=MAX(st[0][st[0][0]],st[1][st[1][0]]);
    105     
    106     _rep(i,st[1][0],1)sum[i]=sum[i+1]+st[1][i];
    107     st[1][st[1][0]+1]=MAXN*10;
    108     
    109     for(i=1,j=st[1][0];i<=st[0][0];i++)
    110     {
    111         while(j&&st[0][i]+st[1][j]+1>=best)j--;j++;
    112         ans0+=sum[j]+int64(st[0][i]+1)*(st[1][0]-j+1)+int64(best)*(j-1);
    113     }
    114     cout<<ans0<<endl;
    115     scanf("\n");
    116     return 0;
    117 }
  • 相关阅读:
    [Android]Android开发艺术探索第13章笔记
    [Android]Android性能优化
    [设计模式]单例模式
    [设计模式]享元模式
    [Android]《Android艺术开发探索》第一章读书笔记
    1.传入:”Welome to Beijing”改为 “Beijing to Welcome” 将字符串按照单词进行逆序,空格作为划分单词的唯一条件
    关于ubuntu.18.04的安装注意事项
    String和Date,Timestamp之间的转换
    判断图片色彩模式 CYMK || RGB
    java copy file
  • 原文地址:https://www.cnblogs.com/oldmanren/p/2679201.html
Copyright © 2020-2023  润新知