Time:2016.08.04
Author:xiaoyimi
转载注明出处谢谢


注意:代码中递归子树时对子树大小的计算有误,虽然可以保证正确性但是会使得求得的子树重心并不正确,可能会被卡掉

传送门
思路
考虑节点x为根时
ansx=Σ(i,j)[i,j∈x的不同子树上的节点]+Σ(i,j)[i,j∈x的相同子树上的节点]ans_x=Σ(i,j)[i,j∈x的不同子树上的节点]+Σ(i,j)[i,j∈x的相同子树上的节点]
可以发现,前一项我们可以通过各节点到x的距离直接求出来,具体做法是做一遍dfs,求得节点与x的距离dis,然后将所有dis排序,O(n)求得(这个比较简单,我就不详细说了)
但这种方法同时也会把相同子树上的节点当成点对算进去,这里面可能有不满足条件的点对,也会让后面的点对重复计算,所以要去掉,具体做法是用相同的方法再计算一遍x的各子树上的∑ansi[i∈x的子节点]\sum ans_i[i∈x的子节点],用ansxans_x减去即可
即我们要求的最终答案为totx=ansx−∑ansi[i∈x的子节点]tot_x=ans_x-\sum ans_i[i∈x的子节点]
后一项实际上就是各个节点的tot,即∑toti[i∈x的子节点\sum tot_i[i∈x的子节点
显然这是可以递归分治求和的
复杂度是神奇的O(nlog2n)O(nlog^2n)
注意:
每次寻找完重心后dis都会改变(这里的dis[i]实际上是i到当前处理的子树的根的距离)
不要全局记录fa
访问的点打标记blabla
话说点分……慢慢来嘛
代码:

#include<cstdio>
#include<algorithm>
#define M 40004
#define LL long long
using namespace  std;
int in()
{int t=0;char ch=getchar();while (ch<'0'||ch>'9') ch=getchar();while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();return t;
}
int n,k,tot,G;
LL ans;
int first[M],siz[M],dis[M],mx[M];
bool vis[M];
struct edge{int u,v,w,next;
}e[M<<1];
void add(int z,int x,int y)
{e[++tot]=(edge){x,y,z,first[x]};first[x]=tot;e[++tot]=(edge){y,x,z,first[y]};first[y]=tot;
}
void dfs(int x,int S,int fa)
{siz[x]=1;mx[x]=0;for (int i=first[x];i;i=e[i].next)if (!vis[e[i].v]&&fa!=e[i].v)dfs(e[i].v,S,x),siz[x]+=siz[e[i].v],mx[x]=max(mx[x],siz[e[i].v]);mx[x]=max(mx[x],S-siz[x]);if (mx[G]>mx[x]) G=x;
}
void form(int x,int D,int fa)
{dis[++dis[0]]=D;for (int i=first[x];i;i=e[i].next)if (!vis[e[i].v]&&fa!=e[i].v)form(e[i].v,D+e[i].w,x);
}
LL cal(int x,int D)
{dis[0]=0;form(x,D,0);LL sum=0;sort(dis+1,dis+dis[0]+1);int l=1,r=dis[0];for (;l<r;)if (dis[l]+dis[r]<=k)sum+=r-l,l++;else r--;return sum;
}
void solve(int x,int S)
{G=0;dfs(x,S,0);x=G;S=siz[x];vis[x]=1;ans+=cal(x,0);for (int i=first[x];i;i=e[i].next)if (!vis[e[i].v])ans-=cal(e[i].v,e[i].w);for (int i=first[x];i;i=e[i].next)if (!vis[e[i].v]) solve(e[i].v,siz[e[i].v]);
}
main()
{mx[0]=M;for (;;){n=in();k=in();if (!n&&!k) break;tot=0;for (int i=1;i<=n;i++) vis[i]=first[i]=0;for (int i=1;i<n;i++) add(in(),in(),in());solve(1,n);printf("%d\n",ans);ans=0;}
}

【POJ1741】Tree,第一次的点分治相关推荐

  1. POJ1741 Tree(树分治——点分治)题解

    题意:给一棵树,问你最多能找到几个组合(u,v),使得两点距离不超过k. 思路:点分治,复杂度O(nlogn*logn).看了半天还是有点模糊. 显然,所有满足要求的组合,连接这两个点,他们必然经过他 ...

  2. 【CF 600E】Lomsat gelral(树上启发式合并, dsu on tree, 静态链分治,模板题)

    Algorithm 名称:树上启发式合并, dsu on tree, 静态链分治 用处:一般用来解决一类不带修改的子树查询问题 核心思想为:利用重链剖分的性质优化子树贡献的计算. 前置知识:启发式合并 ...

  3. POJ1741 Tree 树中点对统计【树分治入门】

    算法合集之<分治算法在树的路径问题中的应用> 论文下载地址 树被定义为没有圈的连通图,有几个性质 在树中去掉一条边后,得到的图是不连通的 在树中添加一条边后,一定存在一条边 树的每一对顶点 ...

  4. POJ1741 Tree(树分治)

    题意: 求树上距离小于等于K的点对有多少个 思路: 每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心 找到重心后,需要统 ...

  5. poj1741 Tree 点分治

    入门题,算是对树分治有了初步的理解吧. #include<iostream> #include<cstdio> #include<cstring> #include ...

  6. POJ1741 Tree(点分治)

    嘟嘟嘟 没错,这一道最经典的点分治模板题. 题意:求树上两点间距离\(\leqslant k\)的点对个数. 点分治这东西我好早就听说了,然后一两个月前也学了一下,不过只是刷了个模板,没往深处学. 对 ...

  7. [poj1741 Tree]树上点分治

    题意:给一个N个节点的带权树,求长度小于等于K的路径条数 思路:选取一个点作为根root,假设f(root)是当前树的答案,那么答案来源于两部分: (1)路径不经过root,那么就是完全在子树内,这部 ...

  8. 【楼天城男人八题】【树分治|Treap+启发式合并】POJ1741 Tree

    题面在这里 待我先膜拜一下楼教主-- 首先这题是很明显的树分治 想说点什么却发现已经没什么好说了 然后我们来看另一种解法:平衡树乱搞 这里用的是Treap实现 对于每个节点,用Treap记录该子树每个 ...

  9. [POJ1741]Tree

    题目大意: 给你一棵带权树,求出树中距离$\leq k$的点对个数. 思路: 运用树上分治的思想,每次找出树的重心,考虑以下三种情况: 1.两个结点在不同子树内,且距离$\leq k$,则算入答案中: ...

最新文章

  1. 软件破解工具整理收集
  2. day29(对象转xml(使用java))
  3. 电路与电子学-第一章直流电路分析方法小概括
  4. 从镜像安装vs2010MSDN,错误“您没有权限修改为帮助内容存储区指定的位子下的内容......
  5. 删除fedora多余内核:解决每次升级后旧内核还会存在的问题
  6. java 基本语法与流程控制_Java基础语法之控制流程
  7. leetcode84. 柱状图中最大的矩形
  8. thymleaf中枚举 判断对象值内容
  9. 计算机另一账户无法使用office,关闭Word文档提示: 如何处理另一个应用程序或用户正在使用的文件?...
  10. [转载] Python数据分析与可视化学习笔记(一)数据分析与可视化概述
  11. js 格式化输出_JS之 调试
  12. JSP-tomcat设置编码格式 配置utf-8(以防网页框以及网页显示的时候中文乱码)
  13. 课时5 企业Web服务器现场抓鸡案例分享
  14. 如何撰写总体设计与详细设计文档
  15. 高中计算机教育类文章,高中信息技术的教学论文
  16. Tomcat启动之后遇到“ran out of the normal time range, it consumed [2000] milliseconds.”?
  17. 阿里云服务器如何进行快照备份
  18. jsp页面转为html5,eclipse 设置jsp页面为HTML5
  19. Python 自动发文章到 wordpress
  20. 尼古拉*特斯拉与通古斯大爆炸

热门文章

  1. k 近邻算法解决字体反爬手段|效果非常好
  2. Android笔记 - android studio导入源码
  3. 找出数组中最大值次大值的一次遍历方法(C++)
  4. LeetCode-94. 二叉树的中序遍历
  5. Python面向过程和面向对象
  6. python 模拟浏览器selenium_Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息示例...
  7. memchache的数据类型_memcache详解
  8. vue用公共组件页面传值_vuejs几种不同组件(页面)间传值的方式
  9. c++解决哥德巴赫猜想问题/c++实现任一大于2的偶数都可以写为两个素数之和
  10. mysql自带客户端连接服务器,客户端连接mysql服务器的指令 mysql -u root -p 详细讲解及使用实例...