hdoj6446(树形DP)
题目链接:https://vjudge.net/problem/HDU-6446
题意:简化题意后就是求距离和的2*(n-1)!倍。
思路:
简单的树形dp,通过求每条边的贡献计算距离和,边(u,v)的贡献为sz[v]*(n-sz[v])。
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- typedef long long LL;
- const int maxn=1e5+;
- const int MOD=1e9+;
- int n,cnt,head[maxn],sz[maxn];
- LL ans;
- struct node{
- int v,nex;
- LL w;
- }edge[maxn<<];
- void adde(int u,int v,LL w){
- edge[++cnt].v=v;
- edge[cnt].w=w;
- edge[cnt].nex=head[u];
- head[u]=cnt;
- }
- void dfs(int u,int fa){
- sz[u]=;
- for(int i=head[u];i;i=edge[i].nex){
- int v=edge[i].v;
- if(v==fa) continue;
- dfs(v,u);
- sz[u]+=sz[v];
- ans=(ans+edge[i].w*sz[v]%MOD*(n-sz[v])%MOD)%MOD;
- }
- }
- int main(){
- while(~scanf("%d",&n)){
- ans=;
- cnt=;
- for(int i=;i<=n;++i)
- head[i]=;
- for(int i=;i<n;++i){
- int u,v;LL w;
- scanf("%d%d%lld",&u,&v,&w);
- adde(u,v,w);
- adde(v,u,w);
- }
- dfs(,);
- for(int i=;i<n;++i)
- ans=ans*i%MOD;
- ans=ans*%MOD;
- printf("%lld\n",ans);
- }
- return ;
- }
另外因为前几天学点分治,看到这题想到可以用点分治求距离和。具体做法是,通过求得重心u后求所有点到重心的距离dis[i],然后采用点分治的第二种写法,遍历u的所有子结点v,用sum表示前面计算过的距离总和,num表示前面的结点数,那么对当前遍历的dis[i],其贡献为num*dis[i]+sum。但要注意不要漏了以重心为端点的边,所以将num初始化1,而不是0。
点分治代码:
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- typedef long long LL;
- const int maxn=1e5+;
- const int MOD=1e9+;
- const int inf=0x3f3f3f3f;
- int n,cnt,head[maxn],sz[maxn],mson[maxn],Min,size,root;
- int vis[maxn],t,num;
- LL dis[maxn],tmp,sum,ans;
- struct node{
- int v,nex;
- LL w;
- }edge[maxn<<];
- void adde(int u,int v,LL w){
- edge[++cnt].v=v;
- edge[cnt].w=w;
- edge[cnt].nex=head[u];
- head[u]=cnt;
- }
- void getroot(int u,int fa){
- sz[u]=,mson[u]=;
- for(int i=head[u];i;i=edge[i].nex){
- int v=edge[i].v;
- if(vis[v]||v==fa) continue;
- getroot(v,u);
- sz[u]+=sz[v];
- mson[u]=max(mson[u],sz[v]);
- }
- mson[u]=max(mson[u],size-sz[u]);
- if(mson[u]<Min) Min=mson[u],root=u;
- }
- void getdis(int u,int fa,LL len){
- dis[++t]=len;
- for(int i=head[u];i;i=edge[i].nex){
- int v=edge[i].v;
- if(vis[v]||v==fa) continue;
- getdis(v,u,(len+edge[i].w)%MOD);
- }
- }
- void solve(int u){
- sum=;
- num=;
- for(int i=head[u];i;i=edge[i].nex){
- int v=edge[i].v;
- if(vis[v]) continue;
- t=;
- tmp=;
- getdis(v,u,edge[i].w);
- for(int i=;i<=t;++i){
- ans=(ans+num*dis[i]%MOD+sum)%MOD;
- tmp=(tmp+dis[i])%MOD;
- }
- sum=(sum+tmp)%MOD;
- num+=t;
- }
- }
- void fenzhi(int u,int ssize){
- vis[u]=;
- solve(u);
- for(int i=head[u];i;i=edge[i].nex){
- int v=edge[i].v;
- if(vis[v]) continue;
- Min=inf,root=;
- size=sz[v]<sz[u]?sz[v]:(ssize-sz[u]);
- getroot(v,);
- fenzhi(root,size);
- }
- }
- int main(){
- while(~scanf("%d",&n)){
- cnt=;
- ans=;
- for(int i=;i<=n;++i)
- head[i]=vis[i]=;
- for(int i=;i<n;++i){
- int u,v;LL w;
- scanf("%d%d%lld",&u,&v,&w);
- adde(u,v,w);
- adde(v,u,w);
- }
- Min=inf,root=,size=n;
- getroot(,);
- fenzhi(root,n);
- for(int i=;i<n;++i)
- ans=ans*i%MOD;
- ans=ans*%MOD;
- printf("%lld\n",ans);
- }
- return ;
- }
hdoj6446(树形DP)的更多相关文章
- 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 ...
- bzoj2500: 幸福的道路(树形dp+单调队列)
好题.. 先找出每个节点的树上最长路 由树形DP完成 节点x,设其最长路的子节点为y 对于y的最长路,有向上和向下两种情况: down:y向子节点的最长路g[y][0] up:x的次长路的g[x][1 ...
随机推荐
- linux系统编程--信号
信号的概念 man 7 siganl 查看man手册 信号在我们的生活中随处可见, 如:古代战争中摔杯为号:现代战争中的信号弹:体育比赛中使用的信号枪......他们都有共性:1. 简单 2. 不能 ...
- sudo/su
linux用户分为根用户/ 普通用户 系统用户 根用户和普通用户是可以实际登录到系统中的,普通用户是没办法使用useradd添加新用户的,只有根用户有权限 当然,也可以使用su su 是切换用户的意思 ...
- 近期将要学习的内容(flag)
块状链表 左偏树 最大流,最小割 费用流 数位DP 计算几何 主席树 树套树(弃疗) 斜率优化 manacher kmp,exkmp 树链剖分 splay树(只看了理论) Trie树 线段树操作及应用 ...
- 【csp模拟赛1】铁路网络 (network.cpp)
[题目描述] 在暑假来临之际,小 Z 的地理老师布置了一个暑假作业,让同学们暑假期间 了解一下 C 国的铁路发展史.小 Z 在多番查证资料后发现,C 国在铁路发展初期, 铁路网络有着一个严密规整的结构 ...
- jQuery系列(十一):jQuery的事件绑定和解绑
1.绑定事件 语法: bind(type,data,fn) 描述:为每一个匹配元素的特定事件(像click)绑定一个事件处理器函数. 参数解释: type (String) : 事件类型 data ( ...
- DPC究竟是什么
DPC究竟是什么 DPC是“Deferred Procedure Call”的缩写,意为推迟了的过程(函数)调用.这是因为,逻辑上应该放在中断服务程序中完成的操作并非都是那么紧迫,其中有一部分可能相对 ...
- linux上安装nginx详细步骤
一.安装依赖包 yum install gcc gcc-c++ pcre-devel patch libffi-devel python-devel zlib-devel bzip2-devel op ...
- [vbs]脚本启动
Set ws = CreateObject("Wscript.Shell") ws.run "cmd.exe /c start tool.exe config_tence ...
- Leetcode题目79.单词搜索(回溯+DFS-中等)
题目描述: 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许 ...
- 在windows系统搭建Flutter开发环境
开发环境搭建(Windows) 系统要求 设置FLutter镜像(非必须) 获取Flutter SDK Android开发环境设置 安装Flutter插件 系统要求 在Windows上要安装并运行Fl ...