博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站
阅读量:6292 次
发布时间:2019-06-22

本文共 1915 字,大约阅读时间需要 6 分钟。

【题意】给定带点权树,要求选择两个点x,y,满足所有点到这两个点中较近者的距离*点权的和最小。n<=50000,h<=100。

【算法】树的重心

【题解】代码参考自:

观察要求容易发现和重心的定义【所有点距离和最小】十分相似。

要把树分成两部分,于是考虑枚举割掉一条边后,在两棵树中各自找重心。

这样做得到的方案虽然不一定满足题意,但最优解一定在方案中,且不满足题意的方案一定不会比最优解小。

用树形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
#include
#include
#define ll long longusing namespace std;const int maxn=50010;const ll inf=1ll<<60;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*3];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]=0; for(int i=first[x];i;i=e[i].from)if(e[i].v!=f){ deep[e[i].v]=deep[x]+1; 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,0,sizeof(first)); tot=0; for(int i=1;i
size[mx2[x]]&&mx[x]!=u)y=mx[x];else y=mx2[x]; if(size[y]*2>size[1])sum+=size[1]-2*size[y],x=y;else break; } x=u; while(1){ if(size[mx[x]]*2>size[u])sum+=size[u]-2*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 0;}
View Code

 

转载于:https://www.cnblogs.com/onioncyc/p/7592511.html

你可能感兴趣的文章
Oracle数据库的语句级读一致性
查看>>
Cannot run Eclipse; JVM terminated. Exit code=13
查看>>
sort与sorted
查看>>
linux下安装和卸载vmware产品
查看>>
Linux系统(一)文件系统、压缩、打包操作总结
查看>>
微信小程序把玩(四十)animation API
查看>>
Android Application中的Context和Activity中的Context的异同
查看>>
MyBatis接口的简单实现原理
查看>>
从0移植uboot (二) _uboot启动流程分析
查看>>
C++异常实现与longjmp, setjmp,栈指针EBP, Active Record
查看>>
Python高级特性(切片,迭代,列表生成式,生成器,迭代器)
查看>>
CISCO知识扫盲
查看>>
[原创]浅谈对华为34岁以上员工“退休”
查看>>
一个hadoop hdfs put 文件失败的小情况
查看>>
C语言 · 计算时间
查看>>
JavaEE开发之Spring中的依赖注入与AOP编程
查看>>
spi flash偶尔出现写入错误的情况
查看>>
Native SBS for Android
查看>>
vue过渡和animate.css结合使用
查看>>
C#编程(七十四)----------释放非托管资源
查看>>