1468: Tree

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1527  Solved: 818
[Submit][Status][Discuss]

Description

给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

Input

N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

Output

一行,有多少对点之间的距离小于等于k

Sample Input

7
1 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10

Sample Output

5
 
/*
思路:
最容易想到的算法是:从每个点出发遍历整棵树,统计数对个数。
由于时间复杂度O(N^2),明显是无法满足要求的。 对于一棵有根树, 树中满足要求的一个数对所对应的一条路径,必然是以下两种情况之一:
1、经过根节点
2、不经过根节点,也就是说在根节点的一棵子树中
对于情况2,可以递归求解,下面主要来考虑情况1。 设点i的深度为Depth[i],父亲为Parent[i]。
若i为根,则Belong[i]=-1,若Parent[i]为根,则Belong[i]=i,否则Belong[i]=Belong[Parent[i]]。
这三个量都可以通过一次BFS求得。
我们的目标是要统计:有多少对(i,j)满足i<j,Depth[i]+Depth[j]<=K且Belong[i]<>Belong[j] 如果这样考虑问题会变得比较麻烦,我们可以考虑换一种角度:
设X为满足i<j且Depth[i]+Depth[j]<=K的数对(i,j)的个数
设Y为满足i<j,Depth[i]+Depth[j]<=K且Belong[i]=Belong[j]数对(i,j)的个数
那么我们要统计的量便等于X-Y 求X、Y的过程均可以转化为以下问题:
已知A[1],A[2],...A[m],求满足i<j且A[i]+A[j]<=K的数对(i,j)的个数 对于这个问题,我们先将A从小到大排序。
设B[i]表示满足A[i]+A[p]<=K的最大的p(若不存在则为0)。我们的任务便转化为求出A所对应的B数组。那么,若B[i]>i,那么i对答案的贡献为B[i]-i。
显然,随着i的增大,B[i]的值是不会增大的。利用这个性质,我们可以在线性的时间内求出B数组,从而得到答案。 综上,设递归最大层数为L,因为每一层的时间复杂度均为“瓶颈”——排序的时间复杂度O(NlogN),所以总的时间复杂度为O(L*NlogN) 然而,如果遇到极端情况——这棵树是一根链,那么随意分割势必会导致层数达到O(N)级别,对于N=10000的数据是无法承受的。因此,我们在每一棵子树中选择“最优”的点分割。所谓“最优”,是指删除这个点后最大的子树尽量小。这个点可以通过树形DP在O(N)时间内求出,不会增加时间复杂度。这样一来,即使是遇到一根链的情况时,L的值也仅仅是O(logN)的。 因此,改进后算法时间复杂度为O(Nlog^2N),可以AC。
/*

学习 思路

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> #define inf 0x3f3f3f3f
#define maxn 40010 using namespace std;
struct node
{
int to,w,next;
}e[maxn<<];
int head[maxn],vis[maxn],son[maxn],deep[maxn],f[maxn],d[maxn];
int n,cnt,root,sum,K,ans,num,x,y,z,L; inline int read()
{
int x=,f=;char c=getchar();
while(c>''||c<''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} inline void add(int u,int v,int dis)
{
e[++num].to=v;e[num].next=head[u];
e[num].w=dis;head[u]=num;
} inline void init()
{
cnt=ans=root=sum=;
memset(head,,sizeof(head));
memset(vis,,sizeof(vis));
memset(deep,,sizeof(deep));
for(int i=;i<n;i++)
{
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
} void get_root(int now,int fa)
{
son[now]=;f[now]=-;
for(int i=head[now];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v]||v==fa) continue;
get_root(v,now);
son[now]+=son[v];f[now]=max(f[now],son[v]);
}
f[now]=max(f[now],sum-son[now]);
if(f[now]<f[root]) root=now;
} void get_deep(int now,int fa)
{
deep[++L]=d[now];
for(int i=head[now];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v]||v==fa) continue;
d[v]=d[now]+e[i].w;
get_deep(v,now);
}
} int cal(int now,int dis)
{
d[now]=dis;L=;get_deep(now,-);
sort(deep+,deep+L+);
int t=;
for(int l=,r=L;l<r;)
{
if (deep[l]+deep[r]<=K) t+=r-l,l++;
else r--;
}
return t;
} void work(int u)
{
ans+=cal(u,);vis[u]=;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v]) continue;
ans-=cal(v,e[i].w);sum=son[v];
root=;get_root(v,);work(root);
}
} int main()
{
freopen("data.txt","r",stdin);
freopen("bzoj1468.txt","w",stdout);
n=read();
init();K=read();
sum=n;f[]=inf;
get_root(,-);
work(root);
printf("%d\n",ans);
return ;
}

代码

#include<cstdio>
#include<algorithm>
#define N 40005
using namespace std;
struct arr{int s,go,next;}a[N*];
int end[N],son[N],f[N],d[N],data[N];
int cnt,L,All,ans,i,x,y,z,n,root,K;
bool Can[N];
void add(int u,int v,int s)
{
a[++cnt].go=v;a[cnt].next=end[u];a[cnt].s=s;end[u]=cnt;
} void Get_root(int k,int fa)
{
son[k]=;f[k]=;
for (int i=end[k];i;i=a[i].next)
{
int go=a[i].go;
if (go==fa||Can[go]) continue;
Get_root(go,k);son[k]+=son[go];
if (son[go]>f[k]) f[k]=son[go];
}
if (All-son[k]>f[k]) f[k]=All-son[k];
if (f[k]<f[root]) root=k;
} void Get_array(int k,int fa)
{
data[++L]=d[k];
for (int i=end[k];i;i=a[i].next)
{
int go=a[i].go;
if (go!=fa&&!Can[go])
d[go]=d[k]+a[i].s,Get_array(go,k);
}
} int calc(int k,int now)
{
d[k]=now;L=;Get_array(k,-);
int A=,l,r;
sort(data+,data+L+);
for (l=,r=L;l<r;)
if (data[r]+data[l]<=K) A+=(r-l),l++;else r--;
return A;
} void work(int k)
{
ans+=calc(k,);Can[k]=;
for (int i=end[k];i;i=a[i].next)
{
int go=a[i].go;
if (Can[go]) continue;
ans-=calc(go,a[i].s);f[root=]=n+;
All=son[go];Get_root(go,-);
work(root);
}
} int main()
{
freopen("data.txt","r",stdin);
freopen("1468.txt","w",stdout);
scanf("%d",&n);
for (i=;i<n;i++)
scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
scanf("%d",&K);All=n;
f[root=]=n+;Get_root(,-);
work(root);
printf("%d",ans);
return ;
}

标程

#include <bits/stdc++.h>

using namespace std;

#define PaiChuCuoWuCaiBREAK true

int main()
{
while(PaiChuCuoWuCaiBREAK)
{
system("data.exe");
system("1468.exe");
system("bzoj1468.exe");
if(system("fc 1468.txt bzoj1468.txt")) {cout<<"lrhdsb";break;}
}
return ;
}

对拍

#include <bits/stdc++.h>

using namespace std;

#define maxn 10004
#define justval 68451
#define justval_ 15641684 int l[maxn],r[maxn],n,lo,ro; int main()
{
freopen("data.txt","w",stdout);
n=rand()%maxn+;printf("%d\n",n);
for(int i=;i<n;i++) l[i]=i+;
lo=n-,r[++ro]=;
for(int just=;just<n;just++)
{
int pos=rand()%lo+;
int pos_=rand()%ro+;
r[++ro]=l[pos];
printf("%d %d %d\n",l[pos],r[pos_],rand()%justval);
for(int i=pos;i<lo;i++) l[i]=l[i+];lo--;
}
printf("%d\n",rand()%justval_);
return ;
}

数据生成 一棵树

bzoj 1468 Tree(点分治模板)的更多相关文章

  1. BZOJ.1468.Tree(点分治)

    BZOJ1468 POJ1741 题意: 计算树上距离<=K的点对数 我们知道树上一条路径要么经过根节点,要么在同一棵子树中. 于是对一个点x我们可以这样统计: 计算出所有点到它的距离dep[] ...

  2. BZOJ 1468 Tree 【模板】树上点分治

    #include<cstdio> #include<algorithm> #define N 50010 #define M 500010 #define rg registe ...

  3. BZOJ 1468: Tree

    Description 真·树,问距离不大于 \(k\) 的点对个数. Sol 点分治. 同上. Code /********************************************* ...

  4. 【刷题】BZOJ 1468 Tree

    Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是 ...

  5. bzoj 1468 Tree 点分

    Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1972  Solved: 1101[Submit][Status][Discuss] Desc ...

  6. POJ - 1741 - Tree - 点分治 模板

    POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...

  7. [洛谷P4178] Tree (点分治模板)

    题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...

  8. POJ1741 Tree 树分治模板

    http://poj.org/problem?id=1741   题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数.   dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...

  9. POJ1741 tree (点分治模板)

    题目大意: 给一棵有 n 个顶点的树,每条边都有一个长度(小于 1001 的正整数).定义 dist(u,v)=节点 u 和 v 之间的最小距离.给定一个整数 k,对于每一对 (u,v) 顶点当且仅当 ...

随机推荐

  1. vs Could Not Connect

    解决,   在win7上卸载IIS 10.0 Express ,安装 IIS7.5 Express

  2. Navicat 导出为 Excel 文件

    1:先选择一个表 再点击导出向导 2:看图   3:选择保存的路径  4:选择字段    5:最后执行吧 

  3. bootstrap table 生成的表格里动态添加HTML元素按钮,JS中添加点击事件,点击没反应---解决办法

    bootstraptable中onExpandRow属性---js  方法添加的 html代码,然后给这代码里面的 元素 添加 事件,却获取不该元素.(称之为未来元素),由于是未来的 所以现在没有这个 ...

  4. Django - app

    1.app目录 migrations:数据库操作的记录(只记录修改表结构的记录); __init__文件:python2中必须填加,python3中无要求,可以不添加: admin:django为我们 ...

  5. Spider-Python实战之通过Python爬虫爬取图片制作Win7跑车主题

    1. 前期准备 1.1 开发工具 Python 3.6 Pycharm Pro 2017.3.2 Text文本 1.2 Python库 requests re urllib 如果没有这些Python库 ...

  6. BZOJ 1631 Usaco 2007 Feb. Cow Party

    [题解] 最短路裸题.. 本题要求出每个点到终点走最短路来回的距离,因此我们先跑一遍最短路得出每个点到终点的最短距离,然后把边反向再跑一遍最短路,两次结果之和即是答案. #include<cst ...

  7. springcloud(五):Eureka提供数据的客户端连接Docker的mysql

    一.提供数据的客户端需要连接数据了,因此需要我们使用mybatis了,等下使用idea生成mybaits和web的依赖 二.提供数据的客户端项目 1.创建项目 2.选择idea自动给我们生成的依赖 3 ...

  8. CentOS6.5下修改MySQL编码方法

    1.查看默认编译,默认登陆到mysql后,通过show variable like命令来查看系统变量 可以看到,默认的数据库编码方式基本设置成了latin1的编译方式,此时我们需要将其修改成utf8的 ...

  9. Linux环境变量设置中配置文件分析(/etc/profile,~/.bashrc等)(转)

    说明:在研究中发现,对于不同版本的Linux系统有着不同的文件,但是总的入口是不变的/etc/profile,下面只是展示加载顺序的研究过程,所以会有些系统没有这个文件等问题. 一.配置文件与作用域: ...

  10. NLS_NCHAR_CHARACTERSET 和 NLS_CHARACTERSET

    SQL> select * from nls_database_parameters; PARAMETER VALUE ------------------------------------- ...