题目:

题解:

bzoj 3302 == 2447 == 2103 三倍经验

首先我们考虑枚举两个中心的位置,然后统计答案.

我们发现,一定有一部分点离第一个中心更近,另一部分点离第二个中心更近

如果将两部分点分别染成两种颜色,容易发现一定有且只有一条边两端的颜色不相同

所以我们考虑枚举这条边,然后将整个树分成两个部分,然后分别求出分开的两颗树的中心,然后把两部分的代价求和来更新答案.

容易发现这样是\(n^2\)的

然后我们回头看题目,发现有奇怪的条件:深度 <= 100

这启发了我们从深度的角度去考虑.

我们考虑枚举这条边的过程,发现其实我们根本不用枚举所有的边

我们考虑在每一个深度上只枚举一条边

换句话说:我们要选择一条从根开始的链,枚举这条链上的每一条边

我们可以从根考虑来选择每一步走哪一棵子树,从而挑选出一条从根开始的链.

这是我们发现:每一次都走子树权值和最大的哪一棵子树,一定是最优决策.

所以我们可以把复杂度降到\(O(nh)\)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(ll &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
typedef long long ll;
const ll maxn = 50005;
const ll inf = 1LL<<60;
struct Edge{
ll v,next;
}G[maxn<<1];
ll n, head[maxn], cnt=1,fa[maxn], dep[maxn], mx[maxn], cmx[maxn];
ll sum[maxn],val[maxn],ans=inf,cut;
inline void add(ll u, ll v) {
G[++cnt] = (Edge){v, head[u]};
head[u] = cnt;
}
inline void dfs(ll x) {
for(ll i = head[x];i; i=G[i].next){
if(G[i].v == fa[x]) continue;
dep[G[i].v] = dep[x] + 1;
fa[G[i].v] = x;
dfs(G[i].v);
sum[x] += sum[G[i].v];
val[x] += val[G[i].v] + sum[G[i].v];
if(mx[x] == 0 || sum[G[i].v] > sum[mx[x]]){
cmx[x] = mx[x];
mx[x] = G[i].v;
}else if(cmx[x] == 0 || sum[G[i].v] > sum[cmx[x]]){
cmx[x] = G[i].v;
}
}
}
inline void find(ll &ret,ll root,ll x,ll k){
ret = min(ret,k);
ll v = mx[x];
if(v == cut || sum[cmx[x]] > sum[mx[x]]) v = cmx[x];
if(v == 0) return;
find(ret,root,v, k + sum[root] - 2*sum[v]);
}
inline void dfss(ll x){
for(ll i = head[x];i;i=G[i].next){
if(G[i].v == fa[x]) continue;
cut = G[i].v;
ll gx = inf,gy = inf;
for(ll j = x; j; j = fa[j]) sum[j] -= sum[cut];
find(gx, 1, 1, val[1] - val[cut] - dep[cut] * sum[cut]);
find(gy, cut, cut, val[cut]);
ans = min(ans, gx + gy);
for(ll j = x; j; j=fa[j]) sum[j] += sum[cut];
dfss(G[i].v);
}
}
int main() {
read(n);
for(ll i=1,u,v;i<n;++i){
read(u);read(v);
add(u, v); add(v, u);
}
for(ll i=1;i<=n;++i) read(sum[i]);
dfs(1);dfss(1);
printf("%lld\n",ans);
getchar();getchar();
return 0;
}

bzoj 3302&2447&2103 树的双中心 树形DP的更多相关文章

  1. 51nod"省选"模测 A 树的双直径(树形dp)

    题意 题目链接 Sol 比赛结束后才调出来..不多说啥了,就是因为自己菜. 裸的up-down dp,维护一下一个点上下的直径就行,一开始还想了个假的思路写了半天.. 转移都在代码注释里 毒瘤题目卡空 ...

  2. bzoj 4871: [Shoi2017]摧毁“树状图”【树形dp】

    做不来--参考https://www.cnblogs.com/ezyzy/p/6784872.html #include<iostream> #include<cstdio> ...

  3. BZOJ3302: [Shoi2005]树的双中心

    BZOJ3302: [Shoi2005]树的双中心 https://lydsy.com/JudgeOnline/problem.php?id=3302 分析: 朴素算法 : 枚举边,然后在两个连通块内 ...

  4. 【BZOJ3302】[Shoi2005]树的双中心 DFS

    [BZOJ3302][Shoi2005]树的双中心 Description Input 第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号.接下来N-1行,每行两个整 ...

  5. 题解-SHOI2005 树的双中心

    SHOI2005 树的双中心 给树 \(T=(V,E)(|V|=n)\),树高为 \(h\),\(w_u(u\in V)\).求 \(x\in V,y\in V:\left(\sum_{u\in V} ...

  6. 【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站

    [题意]给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小.n<=50000,h<=100. [算法]树的重心 [题解]代码参考自:cgh_Andy 观察 ...

  7. BZOJ.2159.Crash的文明世界(斯特林数 树形DP)

    BZOJ 洛谷 挺套路但并不难的一道题 \(Description\) 给定一棵\(n\)个点的树和\(K\),边权为\(1\).对于每个点\(x\),求\(S(x)=\sum_{i=1}^ndis( ...

  8. hdu 4612 Warm up 双连通+树形dp思想

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total S ...

  9. HDU 2242 考研路茫茫—空调教室 (边双连通+树形DP)

    <题目链接> 题目大意: 给定一个连通图,每个点有点权,现在需要删除一条边,使得整张图分成两个连通块,问你删除这条边后,两联通块点权值和差值最小是多少. 解题分析: 删除一条边,使原连通图 ...

随机推荐

  1. js函数的caller属性

    funcName.caller : 返回一个对函数的引用, 该函数调用了当前函数 function test() { if (test.caller) { var a = test.caller.to ...

  2. 【python】-- 文件操作

    一.概述 我们工作中需要经常操作文件,下面就讲讲如何用Python操作文件 1.文件操作的流程: 打开文件,得到文件句柄赋值给一个变量 通过文件句柄,对文件进行操作 关闭文件 #获取文件句柄 f = ...

  3. 全栈JavaScript之路( 二十四 )DOM2、DOM3, 不涉及XML命名空间的扩展

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/hatmore/article/details/37658167 (一)DocumentType 类型 ...

  4. R语言set.seed()函数介绍

    set.seed(),该命令的作用是设定生成随机数的种子,种子是为了让结果具有重复性.如果不设定种子,生成的随机数无法重现.这个函数的主要目的,是让你的模拟能够可重复出现,因为很多时候我们需要取随机数 ...

  5. php类和对象(一)

    对象:任何东西都可以称为对象,类实例化出来的东西类:对所有同类的对象抽象出来的东西 Info: Code,Name,Sex,Nation,Birthday对象:一条具体的信息 p001 张三 男 汉族 ...

  6. 【转】kalman滤波

    Kalman Filter是一个高效的递归滤波器,它可以实现从一系列的噪声测量中,估 计动态系统的状态.广泛应用于包含Radar.计算机视觉在内的等工程应用领域,在控制理论和控制系统工程中也是一个非常 ...

  7. Python问题解决记录

    Python如何进行中文注释:网址 解决Python UnicodeEncodeError: 'ascii' codec can't encode: 网址1.网址2.网址3 Python 字符串转换为 ...

  8. opencv学习之路【四】——opencv文件结构介绍

    这里要感谢这篇博主的文章 部分内容转载自此 opencv在2.3版本之前 都是用的c语言实现的 而在2.3以后的版本 做了很多重大的改变 其中最主要的是用c++重写大部分结构 然后文件的结构和2.0之 ...

  9. POJ 1611并查集

    我发现以后写题要更细心,专心! #include<iostream>#include<algorithm>#include<stdio.h>#include< ...

  10. MHA高可用集群安装配置

    4台服务器 192.168.136.128 主 192.168.136.129 从 192.168.136.130 从 192.168.136.131 管理服务器 一主2从,一管理,安装mysql并配 ...