传送门:点击打开链接
题意:给你一棵树,有点权,求两条不相交的路径的点权和的最大值
思路:Tourist太神辣,这个代码看他的才学会的,但是他只用了10分钟敲了140行..Orz
先一次DFS求出,对于所有的点u,经过这个u点到叶子的路径点权和最大值记为down[u],以及u的子树中一条路径点权和最大值记为best[u]
然后用队列来处理,其实也可以用DFS来处理,那么数组就不能用全局变量了,必须要用vector开在函数内部
对于每个点,把它的子节点的best记录前缀最大和后缀中最大的,down记录前缀最大和次大,后缀最大和次大。
那么就可以开始讨论了,开始枚举第i个儿子,那么我认为第1条链是在第i个儿子的子树中,那么第二条链就不能在第1条链的子树中了,只能是在i节点的左边,或者i节点的右边,或者左边和右边的结合等等,具体可以看代码。
最难想到的就是用前缀和后缀在树上经行处理,写了这道题目后有了这个思想,以后就有助于扩展思路了~
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
LL ans;
int n, ch[MX];
LL A[MX], best[MX], down[MX];
LL pd[MX], pd2[MX], sd[MX], sd2[MX], pb[MX], sb[MX];
int Head[MX], erear;
struct Edge {
int v, nxt;
} E[MX * 2];
struct Data {
int u, f; LL up;
Data() {}
Data(int _u, int _f, LL _up) {
u = _u; f = _f; up = _up;
}
};
void edge_init() {
erear = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
E[erear].v = v;
E[erear].nxt = Head[u];
Head[u] = erear++;
}
void DFS(int u, int f) {
LL Max = 0, Max2 = 0;
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(v == f) continue;
DFS(v, u);
if(down[v] > Max) {
Max2 = Max;
Max = down[v];
} else if(down[v] > Max2) {
Max2 = down[v];
}
best[u] = max(best[u], best[v]);
}
down[u] = Max + A[u];
best[u] = max(best[u], Max + Max2 + A[u]);
}
void solve() {
queue<Data>Q;
Q.push(Data(1, -1, 0));
while(!Q.empty()) {
Data top = Q.front();
Q.pop();
LL up = top.up;
int u = top.u, f = top.f, sz = 0;
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(v == f) continue;
ch[++sz] = v;
}
pb[0] = pd[0] = pd2[0] = 0;
for(int i = 1; i <= sz; i++) {
pd[i] = pd[i - 1];
pd2[i] = pd2[i - 1];
int v = ch[i];
pb[i] = max(pb[i - 1], best[v]);
if(down[v] > pd[i]) {
pd2[i] = pd[i];
pd[i] = down[v];
} else if(down[v] > pd2[i]) {
pd2[i] = down[v];
}
}
sb[sz + 1] = sd[sz + 1] = sd2[sz + 1] = 0;
for(int i = sz; i >= 1; i--) {
sd[i] = sd[i + 1];
sd2[i] = sd2[i + 1];
int v = ch[i];
sb[i] = max(sb[i + 1], best[v]);
if(down[v] > sd[i]) {
sd2[i] = sd[i];
sd[i] = down[v];
} else if(down[v] > sd2[i]) {
sd2[i] = down[v];
}
}
for(int i = 1; i <= sz; i++) {
int v = ch[i];
LL now = A[u] + up + max(pd[i - 1], sd[i + 1]);
now = max(now, max(pb[i - 1], sb[i + 1]));
now = max(now, A[u] + pd[i - 1] + pd2[i - 1]);
now = max(now, A[u] + sd[i + 1] + sd2[i + 1]);
now = max(now, A[u] + pd[i - 1] + sd[i + 1]);
now += best[v];
ans = max(ans, now);
}
for(int i = 1; i <= sz; i++) {
int v = ch[i];
LL nup = max(up, max(pd[i - 1], sd[i + 1])) + A[u];
Q.push(Data(v, u, nup));
}
}
}
int main() {
edge_init(); //FIN;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%I64d", &A[i]);
}
for(int i = 1; i <= n - 1; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge_add(u, v);
edge_add(v, u);
}
DFS(1, -1);
solve();
printf("%I64d\n", ans);
return 0;
}