寻找树上最大权值和的两条不相交的路径。

树形DP题。挺难的,对于我……

定义三个变量ma[MAXN], t[MAXN], sum[MAXN]

其中,ma[i]代表i子树中,最长的路径和

t[i]代表i子树中,用来维护已有一条路径,而且还有一条链从叶子节点到i,则可以从根节点i向上扩展。如下图,维护红色部分

sum[i]维护从某叶子节点到根节点i的最长路径。

转移方程可以看代码,很容易明白

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <set>
#define LL long long using namespace std; const int MAXN = 100050;
const int MOD = 1e9 + 7; LL ans;
LL ma[MAXN], t[MAXN], sum[MAXN];
LL l[MAXN], ml[MAXN], r[MAXN], mr[MAXN];
bool leaf[MAXN];
LL mm[10];
bool vis[MAXN];
int head[MAXN];
struct Edge{
int u, v;
int next;
}edge[MAXN * 2];
int weight[MAXN], par[MAXN];
int n, tot; void addedge(int u, int v){
edge[tot].u = u;
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
} void dfs(int u){
vis[u] = true;
leaf[u] = true;
for(int e = head[u]; e != -1; e = edge[e].next){
int v = edge[e].v;
if(vis[v]) continue;
par[v] = u;
dfs(v);
leaf[u] = false;
}
} void slove(int u){
if(leaf[u]){
ma[u] = t[u] = sum[u] = weight[u];
return ;
} LL m1, m2, M1, M2;
m1 = m2 = M1 = M2 = 0;
for(int e = head[u]; e != -1; e = edge[e].next){
int v = edge[e].v;
if(v != par[u]){
slove(v);
if(ma[v] >= M1){
M2 = M1, M1 = ma[v];
}
else if(ma[v] > M2){
M2 = ma[v];
}
if(sum[v] >= m1){
m2 = m1, m1 = sum[v];
}
else if(sum[v] > m2){
m2 = sum[v];
}
t[u] = max(t[u], t[v] + weight[u]);
}
}
ma[u] = max(M1, m1 + m2 + weight[u]);
sum[u] = m1 + weight[u];
ans = max(ans, M1 + M2); int counts = 0;
for(int e = head[u]; e != -1; e = edge[e].next){
int v = edge[e].v;
if(v != par[u]){
l[++counts] = sum[v];
r[counts] = sum[v];
}
}
l[0] = ml[0] = r[counts + 1] = mr[counts + 1] = 0; //从左往右寻找最大的两个sum for(int i = 1; i <= counts ; i++){
if(l[i] > l[i - 1]) ml[i] = l[i - 1];
else if(l[i] > ml[i - 1]){
ml[i] = l[i];
l[i] = l[i - 1];
}
else{
l[i] = l[i - 1], ml[i] = ml[i - 1];
}
} //从右往左。。。。 for(int i = counts; i >= 1; i--){
if(r[i] > r[i + 1]) mr[i] = r[i + 1];
else if(r[i] > mr[i + 1]){
mr[i] = r[i];
r[i] = r[i + 1];
}
else{
r[i] = r[i + 1], mr[i] = mr[i + 1];
}
} counts = 0;
for(int e = head[u]; e != -1; e = edge[e].next){
int v = edge[e].v;
if(v == par[u]) continue;
counts ++;
mm[0] = l[counts - 1], mm[1] = ml[counts - 1];
mm[2] = r[counts + 1], mm[3] = mr[counts + 1]; sort(mm, mm + 4); ans = max(ans, weight[u] + ma[v] + mm[3] + mm[2]);
ans = max(ans, weight[u] + mm[3] + t[v]);
t[u] = max(t[u], ma[v] + weight[u] + mm[3]);
} } int main(){
scanf("%d", &n);
memset(head, -1, sizeof(head));
// memset(vis, false, sizeof(vis));
// memset(leaf, false, sizeof(leaf));
tot = 0;
memset(t, 0, sizeof(t));
for(int i = 1; i <= n; i++){
scanf("%d", &weight[i]);
}
int u, v;
memset(par, -1, sizeof(par));
for(int i = 0; i < n - 1; i++){
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
dfs(1);
ans = 0;
slove(1); cout << ans << endl;
}

  

Manthan, Codefest 16 F的更多相关文章

  1. Manthan, Codefest 16

    暴力 A - Ebony and Ivory import java.util.*; import java.io.*; public class Main { public static void ...

  2. CF Manthan, Codefest 16 G. Yash And Trees 线段树+bitset

    题目链接:http://codeforces.com/problemset/problem/633/G 大意是一棵树两种操作,第一种是某一节点子树所有值+v,第二种问子树中节点模m出现了多少种m以内的 ...

  3. Manthan, Codefest 16 H. Fibonacci-ish II 大力出奇迹 莫队 线段树 矩阵

    H. Fibonacci-ish II 题目连接: http://codeforces.com/contest/633/problem/H Description Yash is finally ti ...

  4. Manthan, Codefest 16 C. Spy Syndrome 2 字典树 + dp

    C. Spy Syndrome 2 题目连接: http://www.codeforces.com/contest/633/problem/C Description After observing ...

  5. Manthan, Codefest 16 C

    建trie树,刚好字符串是反向的,直接在原图上向前搜索就OK了……………… 可怜的我竟然用了RK来hash,在test67那里T了…… 贴个RK的 #include <iostream> ...

  6. Manthan, Codefest 16 D. Fibonacci-ish

    D. Fibonacci-ish time limit per test 3 seconds memory limit per test 512 megabytes input standard in ...

  7. Manthan, Codefest 16(B--A Trivial Problem)

    B. A Trivial Problem time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  8. Manthan, Codefest 16 -C. Spy Syndrome 2

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  9. Manthan, Codefest 16 -A Ebony and Ivory

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

随机推荐

  1. 引入css的四种方式

    1.内联式引用:直接用在标签上,但维护成本高 style='font-size:16px;color:#000000' 2.外部连接式引用:css代码与html代码分离,便于代码重复使用 <li ...

  2. Angular——MVC模式开发实战

    创建项目 创建工作目录 使用bower下载需要插件 git init.add.commit之后得到分支master,再创建developer分支,然后再此分支上进行具体功能开发 MVC架构 之前小项目 ...

  3. 创建密码带有特殊字符的dblink

    使用的是data studio,所以末尾不加分号 create database link link_to_143 connect " using '(DESCRIPTION = (ADDR ...

  4. WINVER WIN32 WINNT

    WINVER 和 _WIN32_WINNT 请在WINDOWS.H前定义 从 Visual C++ 2008 开始,Visual C++ 不支持面向 Windows 95.Windows 98.Win ...

  5. vue基础---条件渲染

    (1)v-if条件渲染 v-if 指令用于条件性地渲染一块内容.这块内容只会在指令的表达式返回 truthy 值的时候被渲染. 可以用 v-else 添加一个“else 块”: ①表达式 <di ...

  6. BZOJ 2693: jzptab 莫比乌斯反演 + 积性函数 +筛法

    Code: #include<bits/stdc++.h> #define ll long long #define M 10001000 #define maxn 10200100 #d ...

  7. Linux kernel 内存 - 页表映射(SHIFT,SIZE,MASK)和转换(32位,64位)

    0. Intro 如下是在32位下的情况,32位下,只有三级页表:PGD,PMD,PTE 在64位情况下,会有四级页表:PGD,PUD,PMD,PTE 但是原理基本上是一样的,本文主要是想记录一下页表 ...

  8. Java基础——从数组到集合之间关键字的区别!!!!

    1.&& 和 &区别和联系: 相同点 : 结果是一样的.       不同点 :如果使用双&号判断,如果说条件一为false,不会判断条件二,但是单&号会继续判 ...

  9. JSP页面中的动作标识

    JSP页面中的动作标识 制作人:全心全意 包含文件标识<jsp:include> 此标识和include指令类似,用于向当前页面中包含其它的文件,且包含的文件可以是动态文件,也可以是静态文 ...

  10. 基于python、jupyter-notebook 的金融领域用户交易行为分析

    说明:本文重在说明交易数据统计.分析方法,所有数据均为生成的数据 时间原因代码未定义成函数 统计指标:1.用户单日交易行为数据 2.按小时为计算单位,统计用户行为数据(旨在求得一天24小时中每个小时的 ...