http://poj.org/problem?id=1741 (题目链接)

题意

  给出一个n个节点的带权树,求树上距离不超过K的所有点对的个数。

solution  

  点分治裸题。所谓的点分治,就是对于一条路径,只有经过该点和不经过改点两种情况,所以我们可以通过找到树的重心,删去这个点,使树分成几棵小树,再递归处理。不经过的情况很好处理,直接递归到子树就可以了,关键是如何考虑经过的情况。

  对于这道题,我们可以处理处所有点到当前子树重心的距离deep[],然后对于当前子树的两个节点i,j只要满足deep[i]+deep[j]<=K,便符合条件,此时我们发现,这样算出的解是经过当前子树重心的情况,而当i,j都是重心的同一棵儿子节点子树上的点时,会重复计算,因为待会又会递归处理这一子树。所以我们还要减去这一部分的点对,方法同上,只是缩小了树的范围。接着递归处理出解。

  代码hzwer那里模来的,很多细节感觉处理的很优秀,我加了点注释。

代码

// poj1741
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define MOD 1000000007
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline int getint() {
int x=0,f=1;char ch=getchar();
while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} const int maxn=10010;
struct edge {int to,w,next;}e[maxn<<2];
int head[maxn],vis[maxn],son[maxn],deep[maxn],f[maxn],d[maxn],n,cnt,root,sum,K,ans; void insert(int u,int v,int w) {
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w;
}
void init() {
cnt=ans=root=sum=0;
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
memset(deep,0,sizeof(deep));
for (int i=1;i<n;i++) {
int u=getint(),v=getint(),w=getint();
insert(u,v,w);
}
}
void calroot(int u,int fa) { //找重心
f[u]=0;son[u]=1;
for (int i=head[u];i;i=e[i].next) {
if (fa==e[i].to || vis[e[i].to]) continue;
calroot(e[i].to,u);
son[u]+=son[e[i].to];
f[u]=max(f[u],son[e[i].to]);
}
f[u]=max(f[u],sum-son[u]);
if (f[u]<f[root]) root=u;
}
void caldeep(int u,int fa) { //统计当前树中每个节点到重心的距离
deep[++deep[0]]=d[u];
for (int i=head[u];i;i=e[i].next) {
if (e[i].to==fa || vis[e[i].to]) continue;
d[e[i].to]=d[u]+e[i].w;
caldeep(e[i].to,u);
}
}
int cal(int u,int now) {
d[u]=now;deep[0]=0;
caldeep(u,0);
sort(deep+1,deep+deep[0]+1);
int t=0;
for (int l=1,r=deep[0];l<r;) { //这里统计答案的方法很优秀
if (deep[l]+deep[r]<=K) t+=r-l,l++;
else r--;
}
return t;
}
void work(int u) {
ans+=cal(u,0); //统计当前树中所有符合条件的点对
vis[u]=1;
for (int i=head[u];i;i=e[i].next) if (!vis[e[i].to]) {
ans-=cal(e[i].to,e[i].w); //减掉在同一棵子树中的符合条件的节点
sum=son[e[i].to];
root=0;
calroot(e[i].to,0);
work(root); //递归分治处理子树
}
}
int main() {
while (scanf("%d%d",&n,&K)!=EOF && n) {
init();
sum=n;f[0]=inf;
calroot(1,0);
work(root);
printf("%d\n",ans);
}
return 0;
}

  

【poj1741】 Tree的更多相关文章

  1. 【POJ1741】Tree(点分治)

    [POJ1741]Tree(点分治) 题面 Vjudge 题目大意: 求树中距离小于\(K\)的点对的数量 题解 完全不觉得点分治了.. 简直\(GG\),更别说动态点分治了... 于是来复习一下. ...

  2. 【poj1741】Tree 树的点分治

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

  3. 【POJ1741】Tree 树分而治之 模板略?

    做广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog. ...

  4. 【POJ1741】Tree

    题目大意:给定一棵 N 个节点的无根树,边有边权,统计树上边权和不大于 K 的路径数. 对于每条树上路径,对于每一个点来说,该路径只有经过该点和不经过该点两种情况,对于不经过该点的情况,可以转化成是否 ...

  5. 【POJ3237】Tree 树链剖分+线段树

    [POJ3237]Tree Description You are given a tree with N nodes. The tree's nodes are numbered 1 through ...

  6. 【BZOJ】【2631】Tree

    LCT 又一道名字叫做Tree的题目…… 看到删边加边什么的……又是动态树问题……果断再次搬出LCT. 这题比起上道[3282]tree的难点在于需要像线段树维护区间那样,进行树上路径的权值修改&am ...

  7. 【Luogu1501】Tree(Link-Cut Tree)

    [Luogu1501]Tree(Link-Cut Tree) 题面 洛谷 题解 \(LCT\)版子题 看到了顺手敲一下而已 注意一下,别乘爆了 #include<iostream> #in ...

  8. 【BZOJ3282】Tree (Link-Cut Tree)

    [BZOJ3282]Tree (Link-Cut Tree) 题面 BZOJ权限题呀,良心luogu上有 题解 Link-Cut Tree班子提 最近因为NOIP考炸了 学科也炸了 时间显然没有 以后 ...

  9. 【AtCoder3611】Tree MST(点分治,最小生成树)

    [AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...

随机推荐

  1. oracle 事务总结

    用了这么长时间的oracle,该总结一下所得了 1,事务 事务用于保证数据的一致性, 它由一组相关的 dml语句组成, 该组的dml(数据操作语言,增删改,没有查询)语句要么全部成功,要么全部失败,比 ...

  2. JS 关闭 页面 浏览器 事件

    JS监听关闭浏览器事件关键字: js监听关闭浏览器事件Onunload与OnbeforeunloadOnunload,onbeforeunload都是在刷新或关闭时调用,可以在<script&g ...

  3. Java操作符

    几乎所有运算符都只能操作"主类型"(Primitives).例外是"="."= ="和"! =",它们能操作所有对象.除 ...

  4. Html5 Egret游戏开发 成语大挑战(五)界面切换和数据处理

    经过前面的制作,使用Egret的Wing很快完成了开始界面和选关卡界面,下面通常来说就是游戏界面,但此时界面切换和关卡数据还没有准备好,这次讲解界面的切换和关卡数据的解析.前面多次修改了Main.ts ...

  5. LeetCode 2. Add Two Numbers swift

    // // main.swift // leetcode02 // // Created by GuoLa on 16/1/21. // Copyright © 2016年 GuoLa. All ri ...

  6. C#.NET 大型通用信息化系统集成快速开发平台 4.0 版本 - 省市区数据权限的实现效果

    折腾了2-3周,终于把全国网点数据权限,省.市.县数据规范化,查询权限规范化,基础数据规范化的思路理清楚了, 今天应该是一个里程碑式的一天 省市区数据规范化后 1:网点的基础数据可以更加严谨规范化. ...

  7. Ztree 随笔记

    Ztree方法是一个单体对象方法,假如一个页面有多个的话,每申明一个新对象前面的Ztree对象就要被覆盖. 解决:在生成tree控件的时候就要设置其控件ID,然后通过$.fn.zTree.getZTr ...

  8. java中String、StringBuffer、StringBuilder的区别

    java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...

  9. 工作随笔——一次简单的Maven加速构建实战

    注意:所有的编译.打包.部署全部是通过Jenkins完成的. 公司内部有一个项目,开始做的时候已经预计到会有很多客服端.所以开发就搞了如下的结构: fft-api # 公用的API,所有的程序都必须使 ...

  10. C#根据当前时间获取周,月,季度,年度等时间段的起止时间

    最近有个统计分布的需求,需要按统计本周,上周,本月,上月,本季度,上季度,本年度,上年度等时间统计分布趋势,所以这里就涉及到计算周,月,季度,年度等的起止时间了,下面总结一下C#中关于根据当前时间获取 ...