牛客小白月赛22 - 树上子链(树的直径)
链接:https://ac.nowcoder.com/acm/contest/4462/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
给定一棵树 T ,树 T 上每个点都有一个权值。
定义一颗树的子链的大小为:这个子链上所有结点的权值和 。
请在树 T 中找出一条最大的子链并输出。
输入描述:
第一行输入一个 n,1≤n≤105。
接下来一行包含n个数,对于每个数 ai,−105≤ai≤105,表示 i 结点的权值。
接下来有n-1行,每一行包含两个数u,v( 1≤u,v≤n , u != v),表示u与v之间有一条边。
输出描述:
仅包含一个数,表示我们所需要的答案。
输入
5 2 -1 -1 -2 3 1 2 2 3 2 4 2 5
输出
4
说明
样例中最大子链为1 -> 2 -> 5
备注:
一个结点,也可以称作一条链
最开始写的有点麻烦(可忽略):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <stack> 9 #include <queue> 10 #include <set> 11 #include <map> 12 #include <sstream> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const double eps =1e-8; 16 const int mod=1e9+7; 17 const int maxn=1e5+10; 18 using namespace std; 19 20 struct edge 21 { 22 int to; 23 int next; 24 }E[2*maxn];//注意边的条数 25 int head[maxn]; 26 int tot; 27 void add(int u,int v) 28 { 29 E[tot].to=v; 30 E[tot].next=head[u]; 31 head[u]=tot++; 32 } 33 34 LL val[maxn]; 35 int in[maxn]; 36 int out[maxn]; 37 LL ans; 38 39 LL DFS(int u,int fa) 40 { 41 if(out[u]==1&&fa!=-1) 42 return val[u]<0? 0:val[u]; 43 priority_queue<LL,vector<LL>,greater<LL> > qe;//维护子链返回的两个最大值 44 for(int i=head[u];i!=-1;i=E[i].next) 45 { 46 int v=E[i].to; 47 if(v==fa) continue; 48 LL t=DFS(v,u); 49 if(t>0) 50 { 51 if(qe.size()<2) qe.push(t); 52 else 53 { 54 LL p=qe.top(); 55 if(t>p) 56 { 57 qe.pop(); qe.push(t); 58 } 59 } 60 } 61 } 62 LL res=val[u]; 63 if(qe.size()==1) 64 { 65 LL t1=qe.top(); qe.pop(); 66 ans=max(ans,t1); 67 res+=t1; 68 } 69 else if(qe.size()==2) 70 { 71 LL t1=qe.top(); qe.pop(); 72 LL t2=qe.top(); qe.pop(); 73 ans=max(ans,t1+t2+val[u]); 74 res+=t2; 75 } 76 return res<0? 0:res; 77 } 78 79 80 int main() 81 { 82 #ifdef DEBUG 83 freopen("sample.txt","r",stdin); 84 #endif 85 86 int n; 87 scanf("%d",&n); 88 ans=-INF; 89 memset(head,-1,sizeof(head)); 90 for(int i=1;i<=n;i++) 91 { 92 scanf("%lld",&val[i]); 93 ans=max(ans,val[i]); 94 } 95 if(ans<=0) 96 { 97 printf("%lld\n",ans); 98 return 0; 99 } 100 101 for(int i=1;i<=n-1;i++) 102 { 103 int u,v; 104 scanf("%d %d",&u,&v); 105 add(u,v); add(v,u); 106 in[v]++; in[u]++; out[u]++; out[v]++; 107 } 108 for(int i=1;i<=n;i++) 109 { 110 if(in[i]==1) 111 { 112 ans=max(ans,DFS(i,-1)); 113 break; 114 } 115 } 116 printf("%lld\n",ans); 117 118 return 0; 119 }
重新写了一遍:
1 #include <bits/stdc++.h> 2 typedef long long LL; 3 const int INF=0x3f3f3f3f; const LL INFF=0x3f3f3f3f3f3f3f3f; 4 const double eps =1e-8; 5 const int mod=1e9+7; 6 const int maxn=1e5+10; 7 using namespace std; 8 9 LL val[maxn]; 10 vector<int> vt[maxn]; 11 LL ans; 12 13 LL DFS(int u,int fa) 14 { 15 LL res=val[u]; 16 LL max1=-INFF,max2=-INFF; 17 for(int i=0;i<vt[u].size();i++) 18 { 19 int v=vt[u][i]; 20 if(v==fa) continue; 21 LL t=DFS(v,u); 22 if(t>0) 23 { 24 if(t>=max1) max2=max1, max1=t; 25 else if(t>max2) max2=t; 26 } 27 } 28 ans=max(ans, val[u]+max(0LL,max1)+max(0LL,max2)); 29 res+=max(0LL,max1); 30 return res<=0? 0:res; 31 } 32 33 34 int main() 35 { 36 #ifdef DEBUG 37 freopen("sample.txt","r",stdin); 38 #endif 39 40 int n; 41 scanf("%d",&n); 42 ans=-INFF; 43 for(int i=1;i<=n;i++) 44 { 45 scanf("%lld",&val[i]); 46 ans=max(ans,val[i]); 47 } 48 if(ans<=0) 49 { 50 printf("%lld\n",ans); 51 return 0; 52 } 53 54 for(int i=1;i<=n-1;i++) 55 { 56 int u,v; 57 scanf("%d %d",&u,&v); 58 vt[u].push_back(v); 59 vt[v].push_back(u); 60 } 61 ans=max(ans,DFS(1,-1)); 62 printf("%lld\n",ans); 63 64 return 0; 65 }
另一种写法是直接跑两遍DFS就行(类似求树的直径):
1 #include <bits/stdc++.h> 2 typedef long long LL; 3 const int INF=0x3f3f3f3f; const LL INFF=0x3f3f3f3f3f3f3f3f; 4 const double eps =1e-8; 5 const int mod=1e9+7; 6 const int maxn=1e5+10; 7 using namespace std; 8 9 LL val[maxn]; 10 vector<int> vt[maxn]; 11 LL ans; 12 int st; 13 14 void DFS(int u,int fa,LL now) 15 { 16 now+=val[u]; 17 if(ans<now) 18 { 19 ans=now; 20 st=u; 21 } 22 if(now<0) now=0; 23 for(int i=0;i<vt[u].size();i++) 24 { 25 int v=vt[u][i]; 26 if(v==fa) continue; 27 DFS(v,u,now); 28 } 29 } 30 31 int main() 32 { 33 #ifdef DEBUG 34 freopen("sample.txt","r",stdin); 35 #endif 36 37 int n; 38 scanf("%d",&n); 39 ans=-INFF; 40 for(int i=1;i<=n;i++) 41 scanf("%lld",&val[i]); 42 for(int i=1;i<=n-1;i++) 43 { 44 int u,v; 45 scanf("%d %d",&u,&v); 46 vt[u].push_back(v); 47 vt[v].push_back(u); 48 } 49 DFS(1,-1,0); 50 DFS(st,-1,0); 51 printf("%lld\n",ans); 52 53 return 0; 54 }
-