POJ1741 Tree(树的点分治)
题目给一棵边带权的树,统计路径长度<=k的点对数。
楼教主男人八题之一,分治算法在树上的应用。
一开始看论文看不懂,以为重心和距离那些是一遍预处理得来的。。感觉上不敢想每棵子树都求一遍重心和距离——那样时间复杂度怎么会只有O(nlogn)?
后来想通了,真的是对于每颗子树都把其所有结点单独提取出来,而且这么做就是O(nlogn)!
- 首先每次都选择重心进行分治,这样最多大概处理logn层,每一层都包含若干棵子树;
- 考虑每一层的每棵子树要提取的结点个数的和:第一层:n,第二层:n-1(第一层子树个数),第三层:n-(第一层子树个数+第二层子树个数)……不妨就认为每一层都有n个结点的信息要处理,而有logn层,所以其实总共就只有nlogn个(次)结点要处理;
- 对于每一层每棵子树求重心的时间复杂度是线性的,而每层n个结点,最多logn层,所以求重心时间的复杂度就是O(nlogn);
- 对于这道题子树要计算的信息是各个结点到根的距离,然后对其排序并在线性时间复杂度统计点对数目,其处理每棵子树时间复杂度是O(xlogx),x为该子树结点个数;不妨设某层各个子树结点个数为a、b、c……,而a+b+c+……=n,则aloga+blogb+clogc<=nlogn,共logn层,所以处理所有层所有子树信息的时间复杂度就是O(nlog2n);
- 故这一题用点分治的时间复杂度是O(nlog2n)!
写这一题,捋清思路后分了好几个函数逐一实现,感觉框架挺清晰的,提交之后就1A还是很爽的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 11111 struct Edge{
int v,w,next;
}edge[MAXN<<];
int NE,head[MAXN];
void addEdge(int u,int v,int w){
edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u];
head[u]=NE++;
} int n,k,ans;
bool vis[MAXN]; int centre,minimum,size[MAXN];
void getSize(int u,int fa){
size[u]=;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa || vis[v]) continue;
getSize(v,u);
size[u]+=size[v];
}
}
void getCentre(int u,int fa,int &tot){
int res=tot-size[u];
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa || vis[v]) continue;
res=max(res,size[v]);
getCentre(v,u,tot);
}
if(minimum>res){
minimum=res;
centre=u;
}
} int a[MAXN],b[MAXN],an,bn;
void dfs(int u,int fa,int dist){
a[an++]=b[bn++]=dist;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(v==fa || vis[v]) continue;
dfs(v,u,dist+edge[i].w);
}
}
int count(int *c,int &cn){
sort(c,c+cn);
int res=,i=,j=cn-;
while(i<j){
while(i<j && c[i]+c[j]>k) --j;
res+=j-i;
++i;
}
return res;
} void conquer(int u){
an=; a[an++]=;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(vis[v]) continue;
bn=;
dfs(v,u,edge[i].w);
ans-=count(b,bn);
}
ans+=count(a,an);
}
void divide(int u){
getSize(u,u); minimum=INF; getCentre(u,u,size[u]);
u=centre;
vis[u]=;
conquer(u);
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(vis[v]) continue;
divide(v);
}
} int main(){
int a,b,c;
while(scanf("%d%d",&n,&k),(n||k)){
NE=;
memset(head,-,sizeof(head));
for(int i=; i<n; ++i){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c); addEdge(b,a,c);
}
ans=;
memset(vis,,sizeof(vis));
divide();
printf("%d\n",ans);
}
return ;
}
POJ1741 Tree(树的点分治)的更多相关文章
- POJ1741——Tree(树的点分治)
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...
- 【poj1741】Tree 树的点分治
题目描述 Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...
- hdu 4812 D Tree(树的点分治)
D Tree Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others) Total ...
- [poj1741][tree] (树/点分治)
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- POJ1741 Tree 树分治模板
http://poj.org/problem?id=1741 题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数. dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...
- POJ1741(SummerTrainingDay08-G 树的点分治)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 23380 Accepted: 7748 Description ...
- hdu4812-D Tree (树的点分治)
昨天学了下树分治,今天补这道题,还是太不熟练了,写完之后一直超时.后来查出好多错= =比如v,u写倒了,比如+写成了取最值,比如....爆int...查了两个多小时的错..哭...(没想到进首页了 h ...
- 【POJ 1741】 Tree (树的点分治)
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...
- 树上点对统计poj1741(树的点分治)
给定一棵树,边上有权值,要统计有多少对点路径的权值和<=k 分治算法在树的路径中的应用 这个论文里面有分析. 任意两点的路径,要么过根结点,要么在子树中.如果在子树中,那么只要递归处理就行了. ...
- POJ 1741 Tree(树的点分治,入门题)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 21357 Accepted: 7006 Description ...
随机推荐
- Fomo3D代码分析以及漏洞攻击演示
Fomo3D过去的一周内赚足了噱头,一场光明正大的"庞氏"游戏疯狂吸金,在链得得此前的报道中提到"Fomo3D的开发者,是对生态有深刻理解的现实主义者.Fomo3D鼓励黑 ...
- 转载:Android SQLite数据库版本升级原理解析
Android使用SQLite数据库保存数据,那数据库版本升级是怎么回事呢,这里说一下. 一.软件v1.0 安装v1.0,假设v1.0版本只有一个account表,这时走继承SQLiteOpenHel ...
- HeidiSQL安装和使用教程
HeidiSQL 是一个功能非常强大的 MySQL 客户端软件,我们通过它来操作MySQL数据库,比直接通过命令行工具操作要简单的多.我们使用HidiSQL来连接MySQL数据库,MySQL数据库的安 ...
- 使用IDEA新建Maven项目没有完整的项目结构(src文件夹等等)
maven还没加载好,右下角还有进度条在从中央仓库读,所以在创建maven项目的时候,需要加archetypeCatalog=internal 右边新增一项 如下图: 此时就可以快速的建立maven项 ...
- 【bzoj4146】[AMPPZ2014]Divisors 数论
原文地址:http://www.cnblogs.com/GXZlegend/p/6801411.html 题目描述 给定一个序列a[1],a[2],...,a[n].求满足i!=j且a[i]|a[j] ...
- 【Luogu】P3228数列(数学题)
题目链接 考虑我们把所有的增加量拿出来做成一个序列b. 那么在所有n中开头中$1~\sum\limits_{i=1}^{k-1}b[i]$是合法的 也就是说我们枚举所有b[i],然后答案就是$n*m^ ...
- [NC189A]数字权重
题目大意:有一个$n$位的数,设第$i$位为$a_i$(最高位为$a_1$).问满足$(\sum\limits_{i=2}^n(a_i-a_{i-1}))==k$的数的个数(不含前导零) 题解:发现$ ...
- [Codeforces 1027 F] Session in BSU [并查集维护二分图匹配问题]
题面 传送门 思路 真是一道神奇的题目呢 题目本身可以转化为二分图匹配问题,要求右半部分选择的点的最大编号最小的一组完美匹配 注意到这里左边半部分有一个性质:每个点恰好连出两条边到右半部分 那么我们可 ...
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...
- 【ZBH选讲·树变环】
[问题描述] 你是能看到第三题的friends呢.——aoao 树是个好东西,删掉树一条边要1的代价,随便再加一条边有1的代价,求最小的代价把树变成环.[输入格式] 第一行一个整数,代表树的点数.接下 ...