【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站
【题意】给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小。n<=50000,h<=100。
【算法】树的重心
【题解】代码参考自:cgh_Andy
观察要求容易发现和重心的定义【所有点距离和最小】十分相似。
要把树分成两部分,于是考虑枚举割掉一条边后,在两棵树中各自找重心。
这样做得到的方案虽然不一定满足题意,但最优解一定在方案中,且不满足题意的方案一定不会比最优解小。
用树形DP求重心,总复杂度O(n^2)。
观察到最大深度<=100,可以用【往子树权和>sum/2的子树走】的方法求解。
这种做法的正确性:设当前点为重心的答案是ans,则往子树走ans=ans-sum[son]+(sum-sum[son])=ans+sum-2*sum[son],由此可知当sum[son]>sum/2时对答案有贡献。
理解做法后,关键在如何简洁的实现。
对每个点计算size,mx(最大儿子),mx2(次大儿子)。mx只记编号。
计算初始重心答案:s+=size[x],x=2~n。(这里技巧性很强,将所有size都加一次,最底端自然累计了路径数)
枚举边u-v,将边上端v到根的size修改,sum=s后修改sum(这里用sum减去路径数次的size[u],这样就是初始双中心设在1和u了)。
然后从初始双重心往下找重心即可,记得一部分sum是sum[1],另一部分sum是sum[u]。
整个过程的答案只需要:ans+=sum-2*sum[son]。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
const ll inf=1ll<<;
int fa[maxn],deep[maxn],tot,first[maxn],mx[maxn],mx2[maxn],n,w[maxn];
ll ans,size[maxn];
struct edge{int u,v,from;}e[maxn*]; void insert(int u,int v){tot++;e[tot].u=u;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
void dfs(int x,int f){
size[x]=w[x];mx[x]=mx2[x]=;
for(int i=first[x];i;i=e[i].from)if(e[i].v!=f){
deep[e[i].v]=deep[x]+;
fa[e[i].v]=x;
dfs(e[i].v,x);
size[x]+=size[e[i].v];
if(size[e[i].v]>size[mx[x]]){mx2[x]=mx[x];mx[x]=e[i].v;}
else if(size[e[i].v]>size[mx2[x]])mx2[x]=e[i].v;
}
}
int main(){
scanf("%d",&n);
int u,v;
memset(first,,sizeof(first));
tot=;
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
insert(u,v);insert(v,u);
}
for(int i=;i<=n;i++)scanf("%d",&w[i]);
dfs(,);
ll s=;ans=inf;
for(int i=;i<=n;i++)s+=size[i];
for(int k=;k<=tot;k+=){
int u=e[k].u,v=e[k].v;
if(deep[u]<deep[v])swap(u,v);
ll sum=s;
for(int x=v;x;x=fa[x])size[x]-=size[u],sum-=size[u];
int x=,y;
while(){
if(size[mx[x]]>size[mx2[x]]&&mx[x]!=u)y=mx[x];else y=mx2[x];
if(size[y]*>size[])sum+=size[]-*size[y],x=y;else break;
}
x=u;
while(){
if(size[mx[x]]*>size[u])sum+=size[u]-*size[mx[x]],x=mx[x];else break;
}
ans=min(ans,sum);
for(int x=v;x;x=fa[x])size[x]+=size[u];
}
printf("%lld",ans);
return ;
}
【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站的更多相关文章
- BZOJ3302: [Shoi2005]树的双中心
BZOJ3302: [Shoi2005]树的双中心 https://lydsy.com/JudgeOnline/problem.php?id=3302 分析: 朴素算法 : 枚举边,然后在两个连通块内 ...
- 【BZOJ3302】[Shoi2005]树的双中心 DFS
[BZOJ3302][Shoi2005]树的双中心 Description Input 第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号.接下来N-1行,每行两个整 ...
- 题解-SHOI2005 树的双中心
SHOI2005 树的双中心 给树 \(T=(V,E)(|V|=n)\),树高为 \(h\),\(w_u(u\in V)\).求 \(x\in V,y\in V:\left(\sum_{u\in V} ...
- luogu P2726 [SHOI2005]树的双中心
传送门 强行安利->巨佬题解 如果只有一个点贡献答案,那么答案显然是这棵树的带权重心,这个是可以\(O(n)\)求的.一个\(O(n^2)\)暴力是枚举两个集合之间的分界边,然后对这两个集合分别 ...
- 【洛谷 P2726】 [SHOI2005]树的双中心(树的重心)
先考虑一个\(O(N^2)\)做法. 设选的两个点为\(x,y\),则一定可以将树分成两个集合\(A,B\),使得\(A\)集合所有点都去\(x\),\(B\)集合所有点都去\(y\),而这两个集合的 ...
- [SHOI2005]树的双中心
题目链接:Click here Solution: 首先我们要知道,选择两个点\(A,B\),必定存在一条边,割掉这条边,两个集合分别归\(A,B\)管 再结合题目,我们就得到了一个暴力的\(n^2\ ...
- bzoj 3302&2447&2103 树的双中心 树形DP
题目: 题解: bzoj 3302 == 2447 == 2103 三倍经验 首先我们考虑枚举两个中心的位置,然后统计答案. 我们发现,一定有一部分点离第一个中心更近,另一部分点离第二个中心更近 如果 ...
- BZOJ 2103/3302/2447 消防站 树的重心【DFS】【TreeDP】
2103: Fire 消防站 Time Limit: 30 Sec Memory Limit: 259 MBSubmit: 157 Solved: 116[Submit][Status][Disc ...
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
随机推荐
- java沙盒入门(2)
Java在Internet上的应用已经日渐普遍,使用在网页上的Java程序称之为applet,利用Applet的嵌入能够使原本静态的HTML富有变化,并且能够做到"声"." ...
- 【Linux】- 简明Vim练习攻略
vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是一大堆VIM的命令分类,你一定会对这个编辑器失去兴趣的.下面的文章翻译自<Learn Vim Progress ...
- css & text-overflow & ellipsis
css & text-overflow & ellipsis https://developer.mozilla.org/en-US/docs/Web/CSS/text-overflo ...
- TCP建立连接和断开连接过程
假设Client端发起中断连接请求,也就是发送FIN报文.Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着 ...
- HDU2486_A simple stone game
这个题目是这样的,一堆石子有n个,首先第一个人开始可以去1-(n-1)个,接下来两人轮流取石子,每个人可取的石子数必须是一个不超过上一次被取的石子的K倍的整数. 现在求对于一堆数量为n的石子是否为必胜 ...
- BZOJ 1925 地精部落(DP)
一道很经典的DP题. 题意:求n排列中波动排列的种数. 不妨考虑DP,令dp1[i][j],表示1-j的排列中,第一项为i之后递增的波动排列种数.dp2[i][j]表示1-j的排列中,第一项为i之后递 ...
- 【uoj#175】新年的网警 结论题+Hash
题目描述 给出一张 $n$ 个点 $m$ 条边的无向连通图,每条边的边权为1.对于每个点 $i$ ,问是否存在另一个点 $j$ ,使得对于任意一个不为 $i$ 或 $j$ 的点 $k$ ,$i$ 到 ...
- 【转载】Java中的锁机制 synchronized & 偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景 & AtomicReference
参考文章: http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接 ...
- 口胡:[HNOI2011]数学作业
题面 一开始看这题看了好久--觉得这题不可做. 结果是看错题了,我居然看着一段长长的C开头的单词,然后就觉得这是卡特兰数--不知道我在想些什么-- 观察到对于 i = 1~9 : f[i] = f[i ...
- Redis安装与配置Redis安装与配置
今天在使用Redis的时候遇到了一些问题,这个问题的解决,发现很多人使用Redis的时候没有一点安全意识.所以又重温了一下Redis,觉得应该写一下Redis的安全和配置. Redis安装与配置Red ...