【传送门: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. ES学习——分析器和自定义分析器

    简介 es在对文档进行倒排索引的需要用分析器(Analyzer)对文档进行分析.建立索引.从文档中提取词元(Token)的算法称为分词器(Tokenizer),在分词前预处理的算法称为字符过滤器(Ch ...

  2. 第八章 Servlet概述

    第八章 Servlet概述 主要内容: 了解servlet: 掌握servlet实现: 掌握servlet的生命周期. servlet概念 Servlet是运行在服务器端用Java语言编写的应用程序, ...

  3. nginx源代码分析--从源代码看nginx框架总结

    nginx源代码总结: 1)代码中没有特别绕特别别扭的编码实现.从变量的定义调用函数的实现封装,都非常恰当.比方从函数命名或者变量命名就能够看出来定义的大体意义,函数的基本功能,再好的架构实如今编码习 ...

  4. android选择图片或拍照图片上传到server(包含上传參数)

    在9ria论坛看到的.还没測试,先Mark与大家分享一下. 近期要搞一个项目,须要上传相冊和拍照的图片.不负所望,最终完毕了! 只是须要说明一下,事实上网上非常多教程拍照的图片.都是缩略图不是非常清晰 ...

  5. nyist oj 138 找球号(二)(hash 表+位运算)

    找球号(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描写叙述 在某一国度里流行着一种游戏.游戏规则为:现有一堆球中.每一个球上都有一个整数编号i(0<=i< ...

  6. JS,Javascript加载与函数执行过程

    Js,Javascript加载与函数执行过程 test.html <!DOCTYPE HTML> <html lang="en"> <head> ...

  7. ThinkPHP5.0框架开发--第6章 TP5.0 请求和响应

    ThinkPHP5.0框架开发--第6章 TP5.0 请求和响应 第6章 TP5.0 请求和响应 ===================================== 上次复习 1.新建控制器 ...

  8. jsp表单验证格式

  9. oracle数据库回滚

    线下测试数据误操作,回滚攻略--把数据捞出来,这个时间自己设置--表名一定要是:xx_tbd日期 CREATE TABLE user_tbd0718ASselect * from user as of ...

  10. linux SVN服务器创建版本库

    1.安装svn服务 # yuminstall subversion 2.新建一个目录用于存储SVN所有文件    # mkdir /home/svn 3.在上面创建的文件夹中为项目 project_1 ...