题目给一棵边带权的树,统计路径长度<=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(树的点分治)的更多相关文章

  1. POJ1741——Tree(树的点分治)

    1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...

  2. 【poj1741】Tree 树的点分治

    题目描述 Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...

  3. hdu 4812 D Tree(树的点分治)

    D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total ...

  4. [poj1741][tree] (树/点分治)

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

  5. POJ1741 Tree 树分治模板

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

  6. POJ1741(SummerTrainingDay08-G 树的点分治)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 23380   Accepted: 7748 Description ...

  7. hdu4812-D Tree (树的点分治)

    昨天学了下树分治,今天补这道题,还是太不熟练了,写完之后一直超时.后来查出好多错= =比如v,u写倒了,比如+写成了取最值,比如....爆int...查了两个多小时的错..哭...(没想到进首页了 h ...

  8. 【POJ 1741】 Tree (树的点分治)

    Tree   Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...

  9. 树上点对统计poj1741(树的点分治)

    给定一棵树,边上有权值,要统计有多少对点路径的权值和<=k 分治算法在树的路径中的应用 这个论文里面有分析. 任意两点的路径,要么过根结点,要么在子树中.如果在子树中,那么只要递归处理就行了. ...

  10. POJ 1741 Tree(树的点分治,入门题)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description ...

随机推荐

  1. 训练caffe:registry.count(type) == 0 (1 vs. 0) Solver type Nesterov already registered

    命令:./continue-train.sh 内容:../../caffe-master/build/tools/caffe train -gpu=$1 -solver=solver.prototxt ...

  2. Python课程设计 搭建博客

    安装包Github地址 Python综合设计 233博客 注意还有个email文件是需要填入自己信息的,比如最高权限账号和要发送邮件的账号密码 请安装Python2.7环境,本服务器所用环境为 设置环 ...

  3. linux configuration

    sudo vi /etc/profile export JAVA_HOME=/usr/bin/jdk1.8.0_40export JRE_HOME=${JAVA_HOME}/jre  export C ...

  4. nyoj 题目37 回文字符串

    回文字符串 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba".当 ...

  5. CodeForces B. Creating the Contest

    http://codeforces.com/contest/1029/problem/B You are given a problemset consisting of nn problems. T ...

  6. 基于linux操作系统安装、使用redis详解

    服务端安装 Redis的官方下载站是http://redis.io/download,可以去上面下载最新的安装程序下来,我写此文章时的的稳定版本是2.6.11. 步骤一: 下载Redis 进入软件安装 ...

  7. favicon.ico generator

    favicon.ico generator https://www.favicon-generator.org/ https://www.favicon.cc/ https://www.favicon ...

  8. position:absolute和float隐式改变display为inline-block

    不论之前是什么类型的元素(display:none除外), 只要设置了position:absolute或float, 都会让元素以display:inline-block的方式显示, 可以设置长宽, ...

  9. 百度之星复赛T5&&hdu6148

    Problem Description 众所周知,度度熊非常喜欢数字. 它最近发明了一种新的数字:Valley Number,像山谷一样的数字. 当一个数字,从左到右依次看过去数字没有出现先递增接着递 ...

  10. centos 安装squid http代理

    yum -y install squid service squid start service iptables stop