还是DFS——new_bzoj Sta

题目链接: https://vijos.org/d/newbzoj/p/590c9893d3d8a132109937a3

其实题意很简单,先看一下:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

如果暴力的话必然是会TLE的。

所以我们必须想办法。

我记得有一道题是把n次DFS优化为了2次DFS

这道题是不是也可以呢?

我们可以想想。

答案是可以的。

看一下思路:

首先所有点等于父树的点+子树的点。

那么只要求出这两者累加就好了;

子树的总深度简直好求,就是将儿子的总深度+size就好了;

父树的稍微有点麻烦,因为需要一些预处理所以在第二次深搜解决;

对于一个点来说,这个点的父树就是【父亲+父亲的父树+兄弟的子树】;

那么分别累加即可:
注意一下推公式就好;

时间复杂度O(n)
不过有几个细节问题:

1.公式 一定要算好(加减同一项不要消下去。。不然没法调。。)

2.此题需要long long 

后面是代码。

加了一些注释。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 const int maxn=1000005;
 6 using namespace std;
 7 typedef long long ll;
 8 int n,no,to[maxn<<1],next[maxn<<1],head[maxn],cnt;
 9 ll sum[maxn],size[maxn],fas[maxn],ans;
10 void add(int x,int y){
11     to[++cnt]=y;next[cnt]=head[x];head[x]=cnt;
12 }
13 void DFS1(int x,int pre){
14     size[x]=1;int i,y;//size是子树的大小 ,包括x 
15     for(i=head[x];i;i=next[i]){
16         if((y=to[i])!=pre){
17             DFS1(y,x);
18             size[x]+=size[y];
19             sum[x]+=sum[y]+size[y];//sum是深度和,但是不包括x 
20         }
21     }
22 }
23 void DFS2(int x,int pre){
24     int i,y;
25     if(x!=1)fas[x]=fas[pre]+n-size[pre]+sum[pre]-sum[x]-size[x]+size[pre]-size[x]-1+1;
26     //fas[pre]+n-size[pre]是第一部分
27     //sum[pre]-sum[x]-size[x]+size[pre]-size[x]-1 是第二部分
28     //1 是第三部分 
29     //公式要好好理解 
30     if(ans<fas[x]+sum[x]){//fas是父树和 
31         ans=fas[x]+sum[x]; 
32         no=x;
33     }
34     else if(ans==fas[x]+sum[x])no=min(no,x);
35     for(i=head[x];i;i=next[i]){
36         if((y=to[i])!=pre){
37             DFS2(y,x);
38         }
39     }
40 }
41 int main(){
42     //freopen("a.in","r",stdin);
43     scanf("%d",&n);
44     for(int i=1;i<n;i++){
45         int x,y; scanf("%d%d",&x,&y);
46         add(x,y);add(y,x);
47     }
48     DFS1(1,0);DFS2(1,0);
49     printf("%d\n",no);
50     return 0;
51 }

 

上一篇:42. 接雨水


下一篇:sql中某一个字段内容为用逗号分割的字符串转换成多条数据并附Id