题意
给一颗树取出两个不相互包含的子树使权值和最大
当然是选择DP辣~很容易想到枚举以每一个点为根的子树 找到对于这棵子树来说,之外的权值和最大的子树。第一遍dfs可以找出每个点的子树大小以及以每个点为根 所有子树的最大子树,以及这个子树所在的这个点的儿子节点,以及其他个儿子节点找一颗第二大子树。
所以对于每一个树来说,与它对应的最大的 另一棵最大权值子树 在父亲节点对应的最大权值子树 以及 父亲节点的另外孩子包含的最大子树上(感觉有点绕==
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define F first #define S second #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; #define INF 0x7ffffffffffffff typedef long long int LL; #define MAX_N 200005 LL w[MAX_N]; struct no { int v,nexr; }ed[MAX_N*3]; int stu[MAX_N]; int col = 0; void add(int u , int v){ ed[col].v = v; ed[col].nexr = stu[u]; stu[u] = col++; } pair<LL,pair<LL,LL> > ans[MAX_N]; bool flag[MAX_N]; int set[MAX_N]; int cnt[MAX_N]; void dfs(int u){ flag[u] = true; ans[u].F = w[u]; for (int i = stu[u]; i != -1 ; i = ed[i].nexr) { int v = ed[i].v; if(flag[v]) continue; dfs(v); ans[u].F+=ans[v].F; if(ans[v].S.F>ans[u].S.F||ans[v].F>ans[u].S.F){ set[u] = v; ans[u].S.S = ans[u].S.F; ans[u].S.F = max(ans[v].S.F, ans[v].F); } else if(ans[v].S.F>ans[u].S.S||ans[v].F>ans[u].S.S){ ans[u].S.S = max(ans[v].S.F,ans[v].F); } } } LL res[MAX_N]; void dfs2(int u){ flag[u] = true; for (int i = stu[u]; i != -1 ; i = ed[i].nexr) { int v = ed[i].v; if(flag[v]) continue; if(set[u] != v) res[v] = max (ans[u].S.F,res[u]); else res[v] = max (ans[u].S.S,res[u]); dfs2(v); } } int main(int argc, char const *argv[]) { int n; mem(stu,-1); scanf("%d",&n); for (int i = 1; i <= n ; ++i){ scanf("%I64d",&w[i]); ans[i].F = ans[i].S.F = ans[i].S.S = res[i] = -INF; } int u , v; for (int i = 1; i <= n-1 ; ++i) { scanf("%d%d",&u,&v); add(u,v); add(v,u); cnt[u]++; cnt[v]++; } dfs(1); mem(flag,false); dfs2(1); LL pri = -INF; for (int i = 1; i <= n ; ++i) { if(res[i]!=-INF){ pri = max(res[i]+ans[i].F,pri); } } if(pri==-INF) printf("Impossible\n"); else printf("%I64d\n",pri ); return 0; }
时间: 2024-10-22 20:24:16