【传送门: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. 洛谷 P3047 [USACO12FEB]附近的牛Nearby Cows

    P3047 [USACO12FEB]附近的牛Nearby Cows 题目描述 Farmer John has noticed that his cows often move between near ...

  2. hdu 5077 NAND(打表)2014 Asia regional 鞍山站 H题

    题目链接:点击打开链接 题意:就是一个按位运算的一个函数.问最少经过多少步运算能够得到给定数. 思路:不是我投机取巧想打表.是特么这题仅仅能打表.. .打表思想用能够得到的数的集合表示状态bfs:最后 ...

  3. 在Visual Studio Code中使用C#以及.net core

    Working with C# Using .NET Core in Visual Studio Code Note: VS Code does not support debugging appli ...

  4. TYVJ1415 差分约束

    思路: i–>i+1连一条边权为0的边 i–>i-1连一条边权为-1的边 start-1 ->end 连一条边权为w的边 求0->n的最长路即可 //By SiriusRen ...

  5. [原创]微信小程序 实现 圆环 百分百效果

    1.最终效果 2.技术点:a. css3 clip-path , b.根据角度和直边计算另一个直边的长度 3.实现思路: a.3个层(灰色圆形层, 红色圆形层,白色圆形层)  ,其中灰色和红色层大小一 ...

  6. vs2015汉化

    VS2015汉化 VS2015安装打开后默认是英文的,将它改成中文的VS 1.安装下载好的语言包进行安装 2.正在安装 3.安装完成后关闭 4.打开VS2015默认不是中文的,点击Tools--> ...

  7. JavaScript学习——表格的隔行换色+高亮显示

    1.案例一:我们希望在后台页面中实现一个隔行换色的效果显示所有的用户信息,显示效果如下: 1)新标签 <thead> //表头 <tr> <th></th&g ...

  8. HTML基础——网站后台显示页面

    1.框架集标签:(作用:将页面进行区域的划分) <frameset rows="" cols=""> <frame src="&qu ...

  9. 【原创】JAVA word转html

    import java.io.File; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; impor ...

  10. 推荐几个bootstrap 后端UI框架

    转载地址 https://blog.csdn.net/u013816448/article/details/81563051