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. codevs 1281 Xn数列

    题目描述 Description 给你6个数,m, a, c, x0, n, g Xn+1 = ( aXn + c ) mod m,求Xn m, a, c, x0, n, g<=10^18 输入 ...

  2. Html5的一些引擎使用感触

    记得在2011年的时候,51CTO曾经采访我对H5的看法,因为当时Html5小组和雷友的关系,感觉是一片大火的形式,当时我的看法是:第一盈利模式不清晰,第二硬件跟不上,第三技术不成熟. 第一和第二点很 ...

  3. zabbix_proxy安装[yum mysql5.6]

      安装mysql rpm -ivh http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm   修改mysql配置: [m ...

  4. [MetaHook] GameUI hook

    Hook GameUI function. #include <metahook.h> #include <IGameUI.h> IGameUI *g_pGameUI = ; ...

  5. 用python代码做configure文件

    在lua中,我一直用lua作为config文件,或者承载数据的文件 - 好处是lua本身就很好阅读,然后无需额外写解析的代码,还支持在configure文件中读环境变量,条件判断等,方便又强大! (在 ...

  6. 【Flex】正则表达式

    1.基本语法 . 匹配除换行符"\n"外的任意单个字符. * 匹配前面Flex正则表达式的零次或多次出现.eg:Alert.show("ThisBookIsGoodBoo ...

  7. [BZOJ2730][HNOI2012]矿场搭建(求割点)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2730 分析: 如果坍塌的点不是割点,那没什么影响,主要考虑坍塌的点是割点的情况. 显然 ...

  8. win10 进入安全模式的方法

    [收藏] 楼主 水际天成 只看他 2014-12-19 17:53:26 Windows10出问题了,无法加载了,一直停留在鼠标刚刚出现的那个界面,只能看到计算机屏幕变了颜色,然后就没有任何反映了.想 ...

  9. 乱码电路(Garbled circuits)

    乱码电路(Garbled circuits)是Andrew Yao教授在上世纪80年代发明的一种很聪明的技术.它可以让两个人针对某个算式来计算答案,而不需要知道他们在计算式所输入的数字. 举个例子说, ...

  10. javascript数组去重的4个方法

    Array.prototype.unique1 = function(){//有局限性,1,“1”的情况会被去重,因为存入临时对象时,数组中的值被统一转换成了字符串 var obj = {},newA ...