【传送门:BZOJ1468&BZOJ3365


简要题意:

  给出一棵n个点的树,和每条边的边权,求出有多少个点对的距离<=k


题解:

  点分治模板题

  点分治的主要步骤:

  1、首先选取一个点,把无根树变成有根树。 那么如何选点呢? ——树形DP

  因为树是递归定义的,所以我们当然希望递归的层数最小。 每次选取的点,要保证与此点相连的结点数最多的连通块的结点数最小,我们把这个点叫做“重心”

  那么找到一颗树的重心有以下算法:

  (1)dfs一次,算出以每个点为根的子树大小

  (2)记录以每个结点为根的最大子树的大小

  (3)判断:如果以当前结点为根的最大子树大小比当前根更优,更新当前根

  2、处理联通块中通过根结点的路径

  3、标记根结点(相当于处理过后,将根结点从子树中删除)

  4、递归处理以当前点的儿子为根的每棵子树


参考代码(一):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
int x,y,d,next;
}a[];int len,last[];
void ins(int x,int y,int d)
{
len++;
a[len].x=x;a[len].y=y;a[len].d=d;
a[len].next=last[x];last[x]=len;
}
int tot[],root,sum,ms[];
bool v[];
void getroot(int x,int fa)
{
tot[x]=;ms[x]=;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa&&v[y]==false)
{
getroot(y,x);
tot[x]+=tot[y];
ms[x]=max(ms[x],tot[y]);
}
}
ms[x]=max(ms[x],sum-tot[x]);
if(ms[root]>ms[x]) root=x;
}
int dep[],id;
int dd[];
void getdep(int x,int fa)
{
dep[++id]=dd[x];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa&&v[y]==false)
{
dd[y]=dd[x]+a[k].d;
getdep(y,x);
}
}
}
int ans=;
int k;
int cal(int x,int d)
{
dd[x]=d;id=;
getdep(x,);
sort(dep+,dep+id+);
int l=,r=id,c=;
while(l<r)
{
if(dep[l]+dep[r]<=k){c+=r-l;l++;}
else r--;
}
return c;
}
void solve(int x)
{
ans+=cal(x,);
v[x]=true;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(v[y]==false)
{
ans-=cal(y,a[k].d);
sum=tot[y];
root=;getroot(y,x);
solve(root);
}
}
}
int main()
{
int n;
scanf("%d",&n);
len=;memset(last,,sizeof(last));
for(int i=;i<n;i++)
{
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
ins(x,y,d);ins(y,x,d);
}
scanf("%d",&k);
memset(v,false,sizeof(v));
ans=;
sum=tot[]=n;
ms[]=<<-;
root=;getroot(,);
solve(root);
printf("%d\n",ans);
return ;
}

参考代码(二):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
int x,y,d,next;
}a[];int len,last[];
void ins(int x,int y,int d)
{
len++;
a[len].x=x;a[len].y=y;a[len].d=d;
a[len].next=last[x];last[x]=len;
}
int tot[],root,sum,ms[];
bool v[];
void getroot(int x,int fa)
{
tot[x]=;ms[x]=;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa&&v[y]==false)
{
getroot(y,x);
tot[x]+=tot[y];
ms[x]=max(ms[x],tot[y]);
}
}
ms[x]=max(ms[x],sum-tot[x]);
if(ms[root]>ms[x]) root=x;
}
int dep[],id;
int dd[];
void getdep(int x,int fa)
{
dep[++id]=dd[x];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa&&v[y]==false)
{
dd[y]=dd[x]+a[k].d;
getdep(y,x);
}
}
}
int ans=;
int k;
int cal(int x,int d)
{
dd[x]=d;id=;
getdep(x,);
sort(dep+,dep+id+);
int l=,r=id,c=;
while(l<r)
{
if(dep[l]+dep[r]<=k){c+=r-l;l++;}
else r--;
}
return c;
}
void solve(int x)
{
ans+=cal(x,);
v[x]=true;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(v[y]==false)
{
ans-=cal(y,a[k].d);
sum=tot[y];
root=;getroot(y,x);
solve(root);
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
len=;memset(last,,sizeof(last));
for(int i=;i<=m;i++)
{
int x,y,d;char st[];
scanf("%d%d%d%s",&x,&y,&d,st+);
ins(x,y,d);ins(y,x,d);
}
scanf("%d",&k);
memset(v,false,sizeof(v));
ans=;
sum=tot[]=n;
ms[]=<<-;
root=;getroot(,);
solve(root);
printf("%d\n",ans);
return ;
}

BZOJ1468: Tree & BZOJ3365: [Usaco2004 Feb]Distance Statistics 路程统计的更多相关文章

  1. BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治

    BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治 Description     在得知了自己农 ...

  2. bzoj 3365 [Usaco2004 Feb]Distance Statistics 路程统计(点分治,单调)

    [题意] 求树上长度不超过k的点对数目. [思路] 和 Tree 一样一样的. 就是最后统计的时候别忘把根加上. [代码] #include<set> #include<cmath& ...

  3. 【刷题】BZOJ 3365 [Usaco2004 Feb]Distance Statistics 路程统计

    Description 在得知了自己农场的完整地图后(地图形式如前三题所述),约翰又有了新的问题.他提供 一个整数K(1≤K≤109),希望你输出有多少对农场之间的距离是不超过K的. Input 第1 ...

  4. BZOJ 3365: [Usaco2004 Feb]Distance Statistics 路程统计

    Description 一棵树,统计距离不大于 \(k\) 的点对个数. Sol 点分治. 发现自己快把点分治忘干净了... 找重心使所有儿子的最大值尽量小,然后每次处理全部子树,再减去每个子树的贡献 ...

  5. bzoj 3365: [Usaco2004 Feb]Distance Statistics 路程统计【容斥原理+点分治】

    统计在一个root下的两个子树,每个子树都和前面的运算一下再加进去对于这种需要排序的运算很麻烦,所以考虑先不去同子树内点对的算出合法点对个数,然后减去每一棵子树内的合法点对(它们实际上是不合法的,相当 ...

  6. BZOJ 3364: [Usaco2004 Feb]Distance Queries 距离咨询

    Description 一棵树,询问两点间距离. Sol 倍增. 方向没用. 没有然后了. Code /************************************************ ...

  7. 【点分治】poj1741 Tree / poj2114 Boatherds / poj1987 Distance Statistics

    三道题都很类似.给出1741的代码 #include<cstdio> #include<algorithm> #include<cstring> using nam ...

  8. LCA【bzoj3364】 [Usaco2004 Feb]Distance Queries 距离咨询

    Description  奶牛们拒绝跑马拉松,因为她们悠闲的生活无法承受约翰选择的如此长的赛道.因此约翰决心找一条更合理的赛道,他打算咨询你.此题的地图形式与前两题相同.但读入地图之后,会有K个问题. ...

  9. POJ1741 Tree + BZOJ1468 Tree 【点分治】

    POJ1741 Tree + BZOJ1468 Tree Description Give a tree with n vertices,each edge has a length(positive ...

随机推荐

  1. [terry笔记]一个在线美化sql的网站

    http://www.dpriver.com/pp/sqlformat.htm 甚是好用.

  2. COJS 1752. [BOI2007]摩基亚Mokia

    1752. [BOI2007]摩基亚Mokia ★★★   输入文件:mokia.in   输出文件:mokia.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 摩尔瓦 ...

  3. 楼宇自控-BA系统流程总图

    总结一下过程中的节点和技能,希望能对其他人有所帮助

  4. SQL SERVER-主键的建立和删除

    PRIMARY KEY 约束唯一标识数据库表中的每条记录.主键必须包含唯一的值.主键列不能包含 NULL 值.每个表都应该有一个主键,并且每个表只能有一个主键.主键约束操作包含了添加约束和删除约束,修 ...

  5. H2数据库入门使用

    H2数据库入门使用 学习了: https://www.cnblogs.com/xdp-gacl/p/4171024.html http://www.cnblogs.com/xdp-gacl/p/417 ...

  6. HDOJ 2189 悼念512汶川大地震遇难同胞——来生一起走 【母函数】

    题意:非常清楚不解释. 策略:如题. 就是个简单的母函数的改变. 这道题做了好久,才明确是那有毛病,还是理解的不够深刻. AC代码: #include<stdio.h> #include& ...

  7. 强名称程序集(strong name assembly)——为程序集赋予强名称

    ,唯一标识一个程序集 2,放置程序集被仿冒和被篡改. 3,能够部署到全局程序集缓存(GAC:GlobalAssembly Cache)中:在将强名称程序集不熟在GAC其中以后,强名称程序集也能够称为共 ...

  8. lua简单类的实现

    原文地址:http://blog.csdn.net/qqmcy/article/details/37725177 类实现: MyClass = class("MyClass") - ...

  9. class.forName的官方使用方法说明

    原文地址:http://yanwushu.sinaapp.com/class_forname/ 使用jdbc方式链接数据库时会常常看到这句代码:Class.forName(String classNa ...

  10. nova shelve 的使用

    对于云中的资源我们常有例如以下需求 1,用户对临时不使用的VM进行停止操作.以节省费用. 2.对于长时间未使用的VM.管理员想要从hypervisor层面上清除它们从而节省主机资源. 3.但之前的停止 ...