Manthan, Codefest 16 F
寻找树上最大权值和的两条不相交的路径。
树形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的更多相关文章
- Manthan, Codefest 16
暴力 A - Ebony and Ivory import java.util.*; import java.io.*; public class Main { public static void ...
- CF Manthan, Codefest 16 G. Yash And Trees 线段树+bitset
题目链接:http://codeforces.com/problemset/problem/633/G 大意是一棵树两种操作,第一种是某一节点子树所有值+v,第二种问子树中节点模m出现了多少种m以内的 ...
- Manthan, Codefest 16 H. Fibonacci-ish II 大力出奇迹 莫队 线段树 矩阵
H. Fibonacci-ish II 题目连接: http://codeforces.com/contest/633/problem/H Description Yash is finally ti ...
- Manthan, Codefest 16 C. Spy Syndrome 2 字典树 + dp
C. Spy Syndrome 2 题目连接: http://www.codeforces.com/contest/633/problem/C Description After observing ...
- Manthan, Codefest 16 C
建trie树,刚好字符串是反向的,直接在原图上向前搜索就OK了……………… 可怜的我竟然用了RK来hash,在test67那里T了…… 贴个RK的 #include <iostream> ...
- Manthan, Codefest 16 D. Fibonacci-ish
D. Fibonacci-ish time limit per test 3 seconds memory limit per test 512 megabytes input standard in ...
- 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 ...
- Manthan, Codefest 16 -C. Spy Syndrome 2
time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...
- Manthan, Codefest 16 -A Ebony and Ivory
time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...
随机推荐
- Protocol(协议)
Protocol(协议) (一) (1)简介 1.Protocol:就一个用途,用来声明一大堆的方法(不能声明成员变量),不能写实现.看起来类似于一个类的接口, 不同的是协议没有父类,也不能定义实例变 ...
- 测试端口是否开放用PIN还是telnet命令
有时候很想知道一个IP的某个端口是否开放,那么你会用什么命令来测试呢?是ping还是telnet? 其实正确的方法应该是telnet命令.因为用ping命令的话不管你ping哪个端口,只要这个IP地址 ...
- mongodb数据库命令
常用数据库命令汇总 Database Commands Api 下面简单列一下Shell常用的基本命令 启动连接Mongodb #带配置信息启动 mongod -f xxx.conf #连接 mong ...
- CUDA 显存操作:CUDA支持的C++11
CUDA9的编译器和语言改进 使用CUDA 9,nvcc编译器增加了对C ++ 14的支持,其中包括新功能 通用的lambda表达式,其中使用auto关键字代替参数类型; auto lambda = ...
- SQlite数据库框架:LitePal
常用的数据库框架Android的发展的速度是难以置信的,Android出来哪一年我还在小学上学很,还能很清楚的记得,那年一切,但是那个时候的我怎么可能也不会想到自己将来会要去做Android.Andr ...
- Java笔记——String、StringBuffer和StringBuilder类
String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符串序列是不可改变的,直至这个对象被销毁. StringBuffer对象则代表一个字符序列可变的字符串,当一个S ...
- IOS上MediaPlayer framework实现视频播放
播放电影文件: iOS sdk中可以使用MPMoviePlayerController来播放电影文件.但是在iOS设备上播放电影文件有严格的格式要求,只能播放下面两个格式的电影文件. • H.264 ...
- 迭代器,生成器(generator)和Promise的“微妙”关系
需要Promise源码版的朋友:传送链接 本文主要讲述(iterator)和生成器*/yield之间的联系和各自的用法,以及生成器的高配版本aysnc/await的使用. 大纲: 迭代器(iterat ...
- 【最短路】Dijkstra+ 链式前向星+ 堆优化(优先队列)
Dijkstra+ 链式前向星+ 优先队列 Dijkstra算法 Dijkstra最短路算法,个人理解其本质就是一种广度优先搜索.先将所有点的最短距离Dis[ ]都刷新成∞(涂成黑色),然后从起点 ...
- 『 Luogu P3205 』 HNOI2010 合唱队
解题思路 设置两个二维数组 $f$ 和 $g$,含义如下. $f[l][r]$ 表示在期望得到的队形中 $l\rightarrow r$ 这段区间初始队形排列的方案数,并且最后一个加入进去的是第 $l ...