算法合集之《分治算法在树的路径问题中的应用》
论文下载地址
树被定义为没有圈的连通图,有几个性质

  1. 在树中去掉一条边后,得到的图是不连通的
  2. 在树中添加一条边后,一定存在一条边
  3. 树的每一对顶点U和V之间有且只有一条路径

分治

分而治之,将一个问题分割成一些规模较小的相互独立的子问题 ,通常在一个线性结构上分治,分至算法在树结构上的应用称为树分治算法

  • 基于点的分治
    首先,选取一个点将无根树转化为有根树,再递归处理以根节点的儿子为根的子树
    我们选取一个点,要求将其删除后,节点最多的树的节点个数最小,这个点被称为 树的重心 .
    可以用树上的动态规划解决,时间复杂度为O(n),n为树的节点总数

  • 基于边的分治
    在树中选取一条边,将原树分为两棵不相交的树,递归处理
    选取的边要满足所分离出来的两棵子树的节点个数尽量平均,这条边称为 中心边
    可以用树上的动态规划解决,时间复杂度为O(n),n为树的节点总数

定理1
存在一个点使得分出的子树的节点个数均不大于 N/2

定理2
如果一棵树中,每个点的度均不大于D,那么存在一条边使得分出两棵子树的节点个数在 [N/(D+1),N*(D+1)],(N>=2)

POJ1741

题意
给定一个N个节点的带权树,定义dist(u,v)为u,v两点之间的最短路径长度,路径长度定义为路径上所有边的权和。对于两个不同的点a,b,如果满足dist(a,b)<=k,称为合法点对,求合法点对的个数

#include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#include<sstream>
#include<cstdio>
#include<cmath>
#include<climits>
using namespace std;
const int maxn=1e4+7;
const int inf=0x3f3f3f3f;
typedef long long ll;
const int mod=1e9+7;
int n,k,allnode;
int head[maxn*2];
int num;
int dp[maxn];
int size[maxn];
int Focus,M;
ll dist[maxn];
int deep[maxn];
bool vis[maxn];
ll ans;
struct Edge
{int u,v,w,next;
}edge[maxn<<2];
void addEdge(int u,int v,int w)
{edge[num].u=u;edge[num].v=v;edge[num].w=w;edge[num].next=head[u];head[u]=num++;
}
void init()
{memset(head,-1,sizeof(head));memset(dist,0,sizeof(dist));memset(vis,0,sizeof(vis));num=0;
}
void getFocus(int u,int pre)
{size[u]=1;dp[u]=0;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==pre||vis[v]) continue;getFocus(v,u);size[u]+=size[v];dp[u]=max(dp[u],size[v]);}dp[u]=max(dp[u],allnode-size[u]);if(M>dp[u]){M=dp[u];Focus=u;}
}
void dfs(int u,int pre)
{deep[++deep[0]]=dist[u];for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v,w=edge[i].w;if(v==pre||vis[v]) continue;dist[v]=dist[u]+w;dfs(v,u);}
}
int cal(int x,int now)
{dist[x]=now,deep[0]=0;dfs(x,0);sort(deep+1,deep+deep[0]+1);int ans=0;for(int l=1,r=deep[0];l<r;){if(deep[l]+deep[r]<=k){ans+=r-l;l++;}else r--;}return ans;
}
void solve(int x)
{vis[x]=1;ans+=cal(x,0);for(int i=head[x];i!=-1;i=edge[i].next){int v=edge[i].v;if(vis[v]) continue;ans-=cal(v,edge[i].w);allnode=size[v];Focus=0,M=1e9;getFocus(v,x);solve(Focus);}
}
int main()
{#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifwhile(scanf("%d%d",&n,&k)!=EOF&&(n+k)){init();for(int i=1,u,v,w;i<n;i++){scanf("%d%d%d",&u,&v,&w);addEdge(u,v,w);addEdge(v,u,w);}Focus=ans=0;allnode=n,M=1e9;getFocus(1,0);solve(Focus);printf("%lld\n",ans);}return 0;
}

聪聪可可 HYSBZ - 2152

链接

题意

这道题和POJ1741非常类似,这里只不过多了一步转化,要处理3的倍数,在建图和统计的时候都进行模3操作,这样最后两个点之间的距离只可能是0,1,2,然后就可以用他们组合为3的倍数,首先0和0组合,1和2组合,2和1组合【题中(1,2)和(2,1)不同】 分子可以由树分治求出来,分母必然是N*N

#include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#include<sstream>
#include<cstdio>
#include<cmath>
#include<climits>
using namespace std;
const int maxn=2e4+7;
const int inf=0x3f3f3f3f;
typedef long long ll;
const int mod=1e9+7;
int n,k,allnode;
int head[maxn*2];
int num;
int dp[maxn];
int size[maxn];
int Focus,M;
ll dist[maxn];
int deep[maxn];
bool vis[maxn];
int ans;
int cnt[4];
struct Edge
{int u,v,w,next;
}edge[maxn<<2];
void addEdge(int u,int v,int w)
{edge[num].u=u;edge[num].v=v;edge[num].w=w;edge[num].next=head[u];head[u]=num++;
}
void init()
{memset(head,-1,sizeof(head));memset(dist,0,sizeof(dist));memset(vis,0,sizeof(vis));num=0;
}
void getFocus(int u,int pre)
{size[u]=1;dp[u]=0;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==pre||vis[v]) continue;getFocus(v,u);size[u]+=size[v];dp[u]=max(dp[u],size[v]);}dp[u]=max(dp[u],allnode-size[u]);if(M>dp[u]){M=dp[u];Focus=u;}
}
void dfs(int u,int pre)
{cnt[deep[u]]++;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==pre||vis[v]) continue;deep[v]=(deep[u]+edge[i].w)%3;dfs(v,u);}
}
int cal(int x,int now)
{deep[x]=now;cnt[0]=cnt[1]=cnt[2]=0;dfs(x,0);return cnt[1]*cnt[2]*2+cnt[0]*cnt[0];
}
void solve(int x)
{ans+=cal(x,0);vis[x]=1;for(int i=head[x];i!=-1;i=edge[i].next){int v=edge[i].v;if(vis[v]) continue;ans-=cal(v,edge[i].w);allnode=size[v],M=1e9,Focus=0;getFocus(v,x);solve(Focus);}
}
int main()
{#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifscanf("%d",&n);init();for(int i=1,u,v,w;i<n;i++){scanf("%d%d%d",&u,&v,&w);addEdge(u,v,w%3);addEdge(v,u,w%3);}allnode=n,Focus=0,M=1e9;getFocus(1,0);solve(Focus);int t=__gcd(ans,n*n);printf("%d/%d\n",ans/t,n*n/t);return 0;
}

POJ1741 Tree 树中点对统计【树分治入门】相关推荐

  1. Tree(树分治入门)

    题目链接:http://poj.org/problem?id=1741 Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions ...

  2. 【楼天城男人八题】【树分治|Treap+启发式合并】POJ1741 Tree

    题面在这里 待我先膜拜一下楼教主-- 首先这题是很明显的树分治 想说点什么却发现已经没什么好说了 然后我们来看另一种解法:平衡树乱搞 这里用的是Treap实现 对于每个节点,用Treap记录该子树每个 ...

  3. POJ1741:Tree——题解+树分治简要讲解

    http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. -------------------- 以这道题为例记录一下对于树分治的理解. 树 ...

  4. POJ 1741 Tree 树分治

    题意: 给出一颗有\(n (n \leq 10^4)\)个节点的树,和一个\(k\).统计有多少个点对\(u, \, v(u \neq v)\)满足\(u\)到\(v\)的最短距离不超过\(k\). ...

  5. [poj1741 Tree]树上点分治

    题意:给一个N个节点的带权树,求长度小于等于K的路径条数 思路:选取一个点作为根root,假设f(root)是当前树的答案,那么答案来源于两部分: (1)路径不经过root,那么就是完全在子树内,这部 ...

  6. poj1741 Tree 点分治

    入门题,算是对树分治有了初步的理解吧. #include<iostream> #include<cstdio> #include<cstring> #include ...

  7. 点分治(树分治)详解

    作者: hsez_yyh 链接:https://blog.csdn.net/yyh_getAC/article/details/126696654 来源:湖北省黄石二中信息竞赛组        著作权 ...

  8. FZU 2087 统计树边【MST相关】

     Problem 2087 统计树边 Accept: 212    Submit: 651 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Prob ...

  9. 树分治树链剖分相关题目讨论

    预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs.c ...

最新文章

  1. linux+swig+python,linux下使用swig让python调用C++(复杂版:包括多文件调用和链接库)...
  2. 第一天:数据库设计--access数据类型介绍
  3. Docker 镜像小结 - 每天5分钟玩转 Docker 容器技术(21)
  4. UIWebView如何加载本地图片
  5. 中国国际智能产业博览会-2018-08-23至25 重庆国际博览中心举行
  6. Redis源码解析:21sentinel(二)定期发送消息、检测主观下线
  7. Mysql数据库及帐号的权限查询
  8. 怎么把php写入文件格式,如何将一个PHP数组有格式的写入文件中
  9. Nodejs实现的一个静态服务器例子
  10. 小程序:版本更新后获取用户信息变更
  11. UVa 1588 - Kickdown(BUG)
  12. excel表中怎么插入visio_Microsoft Visio2007中vsdx文件怎么打开|Visio插入表格方法
  13. Navicat删除注册表
  14. 日本公司推出第一款MR购物应用,今秋上市
  15. 听听那冷雨 -- 余光中
  16. Androild Killer无法运行,出现Runtime error 217
  17. 个人任务管理系统-数据库
  18. Linux程序动态库的加载
  19. 中国文化产业基地(园区)前景预测和发展战略规划建议报告2021年版
  20. “阿里云大数据技术实战训练营”江苏省大学生万人计划学术冬令营活动成功举行...

热门文章

  1. ajax实现简单的点击左侧菜单,右侧加载不同网页
  2. RE:SB的SDOISB记
  3. linux系统下用到的小知识点积累
  4. 【经验总结】VS2010下建立MFC程序
  5. FCKeditor使用方法技术详解
  6. Flesch Reading Ease(模拟)
  7. (转)flex中使用swc实现更好的界面代码分离
  8. HP6531s安装windows2003无法调节亮度的解决方法
  9. matlab参考答案2011至诚,职高数学试卷答卷答案详解
  10. 这就是计算机男用英语怎么说,科学网—Is a computer male or female? 计算机是男的还是女的? - 邱敦莲的博文...