【hdu6613】Squrirrel 树形DP
题意:给一个带权树,求把一条边的权值变成0,再选一个点做根,最大深度最小是多少。 \(\sum n \le 10^6\)
key:树形DP
题里有边权小于等于200,然而并没有什么用。
首先做出 \(h_{u,0/1}\) 表示 u 的子树中不删边/删边,从 u 向下连出去的最长链是多少。
然后再 dfs 一遍。 dfs(u,w0,w1) 为当前在点 u,u 子树外不删边/删边的最长链。结合 \(h_{u,0/1}\) 就能知道以 u 为根的答案了。
具体来说,这里的情况只有在子树内删边/在子树外删边,向下 dfs 的时候也要注意 w0 和 w1 是怎么递推的。这些都比较麻烦,需要记录一些前缀后缀和。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 1e6 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
const LD eps = 1e-8;
LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
}
struct edge {
int t,d;
};
vector<edge> G[SZ];
int f[SZ][2],h[SZ];
void dfs1(int u,int fa) {
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) continue;
dfs1(v,u);
}
int premax[G[u].size()+1][2] = {};
int sufmax[G[u].size()+1][2] = {};
memset(premax,0,sizeof premax);
memset(sufmax,0,sizeof sufmax);
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) {
if(i==0) continue;
premax[i][0] = premax[i-1][0];
continue;
}
if(i==0)
premax[i][0] = f[v][0] + e.d;
else
premax[i][0] = max(premax[i-1][0],f[v][0]+e.d);
}
for(int i = G[u].size()-1;i >= 0;i --) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) {
sufmax[i][0] = sufmax[i+1][0];
continue;
}
sufmax[i][0] = max(sufmax[i+1][0],f[v][0]+e.d);
}
f[u][0] = 0,f[u][1] = INF;
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) continue;
int o;
if(i==0) o = sufmax[i+1][0];
else o = max(premax[i-1][0],sufmax[i+1][0]);
f[u][0] = max(f[u][0],f[v][0] + e.d);
f[u][1] = min(f[u][1],max(o,min(f[v][0],f[v][1] + e.d)));
}
}
void dfs2(int u,int fa,int w0,int w1) {
int delval[G[u].size()+1] = {};
int nodelval[G[u].size()+1] = {};
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) continue;
delval[i] = min(f[v][0],f[v][1]+e.d);
nodelval[i] = f[v][0] + e.d;
}
int P[G[u].size()+1][2] = {};
int S[G[u].size()+1][2] = {};
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) {
if(i) P[i][0] = P[i-1][0],P[i][1] = P[i-1][1];
continue;
}
if(i==0) P[i][0] = nodelval[i],P[i][1] = delval[i];
else {
P[i][0] = max(P[i-1][0],nodelval[i]);
P[i][1] = min(max(P[i-1][0],delval[i]),max(P[i-1][1],nodelval[i]));
}
}
S[G[u].size()][0] = 0; S[G[u].size()][1] = INF;
for(int i = G[u].size()-1;i >= 0;i --) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) {
S[i][0] = S[i+1][0]; S[i][1] = S[i+1][1];
continue;
}
S[i][0] = max(S[i+1][0],nodelval[i]);
S[i][1] = min(max(S[i+1][0],delval[i]),max(S[i+1][1],nodelval[i]));
}
//*****************************************/
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) continue;
int o,p;
if(i==0) o = S[i+1][0],p = S[i+1][1];
else {
o = max(P[i-1][0],S[i+1][0]);
p = min(max(P[i-1][1],S[i+1][0]),max(P[i-1][0],S[i+1][1]));
}
int ww0 = max(w0+e.d,o+e.d);
int ww1 = min(max(w1+e.d,o+e.d),min(max(w0+e.d,p+e.d),max(w0,o)));
/* cout << p << endl;
printf("%d %d %d %d|%d %d %d\n",u,v,ww0,ww1,
max(w1+e.d,o+e.d),max(w0+e.d,p+e.d),max(w0,o));*/
dfs2(v,u,ww0,ww1);
}
/*
printf("%d : \n",u);
for(int i = 0;i < G[u].size();i ++) printf("%3d",G[u][i]); puts("");
for(int i = 0;i < G[u].size();i ++) printf("%3d",premax[i][0]); puts("");
for(int i = 0;i < G[u].size();i ++) printf("%3d",sufmax[i][0]); puts("");
for(int i = 0;i < G[u].size();i ++) printf("%3d",premax[i][1]); puts("");
for(int i = 0;i < G[u].size();i ++) printf("%3d",sufmax[i][1]); puts("");
*/
h[u] = 0;
int maxn = 0;
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) continue;
maxn = max(maxn,nodelval[i]);
}
h[u] = max(w1,maxn);
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i].t;
edge e = G[u][i];
if(v == fa) continue;
int o;
if(i==0) o = S[i+1][0];
else o = max(P[i-1][0],S[i+1][0]);
h[u] = min(h[u],max(max(w0,min(f[v][0],f[v][1]+e.d)),o));
}
}
int main() {
// freopen("1.in","r",stdin); freopen("1.out","w",stdout);
int T = read();
while(T --) {
int n = read();
for(int i = 1;i <= n;i ++) G[i].clear();
for(int i = 1;i < n;i ++) {
int u = read(),v = read(),w = read();
G[u].push_back((edge){v,w});
G[v].push_back((edge){u,w});
}
dfs1(1,0);
dfs2(1,0,-INF,-INF);
int ans = 1e9;
/* for(int i = 1;i <= n;i ++) printf("%5d",i); puts("");
for(int i = 1;i <= n;i ++) printf("%5d",h[i]); puts("");
for(int i = 1;i <= n;i ++) printf("%5d",f[i][0]); puts("");
for(int i = 1;i <= n;i ++) printf("%5d",f[i][1]); puts("");*/
int id = -1;
for(int i = 1;i <= n;i ++) if(ans > h[i]) ans = h[i],id = i;
printf("%d %d\n",id,ans);
}
}
/**
1
10
2 1 139
3 1 72
4 2 141
5 2 133
6 5 121
7 5 49
8 7 182
9 5 174
10 9 171
1
9
2 1 1
3 2 9
4 1 8
5 1 1
6 1 9
7 3 9
8 6 5
9 5 8
*/
【hdu6613】Squrirrel 树形DP的更多相关文章
- HDU 6613 Squrirrel 树形dp
题意:给你一颗树,你可以把这棵树上的一条边的边权变为0,现在让你选一个根,让所有点到这个点的最大距离尽量的小.如果有多个根的最大距离距离相同,输出编号最小的边. 思路:如果没有把边权变为0的操作,这个 ...
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
- COGS 2532. [HZOI 2016]树之美 树形dp
可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...
- 【BZOJ-4726】Sabota? 树形DP
4726: [POI2017]Sabota? Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 128 Solved ...
- 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
- 树形DP
切题ing!!!!! HDU 2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- POJ2342 树形dp
原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...
- hdu1561 The more, The Better (树形dp+背包)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...
随机推荐
- cf 1241 D. Sequence Sorting(思维)
题意: 一个序列有n个数,有一种操作,你可以选一个数x,使这个序列中等于x的数都移到序列头或尾. 问最少几次操作后,可以使这个序列非降序. 思路: (以下说bi移动到哪里,其实就是指a1……an中等于 ...
- 【剑指Offer】面试题12. 矩阵中的路径
题目 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左.右.上.下移动一格.如果一条路径经过了矩阵的某一格,那么该路径 ...
- oracle11g数据库的安装
先在 Oracle官网上下载11g oracle Database 11g 第 2 版 (11.2.0.1.0) 标准版.标准版 1 以及企业版,适用于 Microsoft Windows (x6 ...
- 【Android】家庭记账本手机版开发报告二
一.说在前面 昨天 完成了对记账本的账单的增删 今天 完善昨天的框架结构( 1.引入ViewModel管理数据.使MainActive 只管理界面.不再管数据了 2.引入AsyncTask.后台执行. ...
- HDU - 6043 KazaQ's Socks(找规律)
题意:有n双袜子,编号1到n,放在衣柜里,每天早晨取衣柜中编号最小的袜子穿,晚上将这双袜子放在篮子里,当篮子里有n-1双袜子时,清洗袜子,直到第二天晚上才洗好,并将洗好的袜子重新放回衣柜. 分析:规律 ...
- EUI库 - 10 - 使用自定义组件
步骤 1 在根节点,添加一个自定义的命名空间 2 可以设置skinName 自定义组件规范 1 不复用的不要用自定义组件 2 属性必须要有默认值(赋值为null也可以),因为TS编译器会把没有默 ...
- 解决fixed布局里内容不滚动问题
//注意给父级加上 (1)横向滚动 left:0; right:0; 然后想要横向滚动的话 overflow-x:scroll; overflow-y:hidden; (2)竖直方向滚动top:0;b ...
- 一个例子搞清楚Java程序执行顺序
当我们new一个GirlFriend时,我们都做了什么? 一个例子搞懂Java程序运行顺序 public class Girl { Person person = new Person("G ...
- POJ 1995:Raising Modulo Numbers 快速幂
Raising Modulo Numbers Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 5532 Accepted: ...
- 201609-2 火车购票 Java
思路待补充 import java.util.Scanner; class Main{ public static void main(String[] args) { //100个座位 int[] ...