poj 1741 Tree(树的点分治)
poj 1741 Tree(树的点分治)
给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对。
首先对于一个树中的点对,要么经过根结点,要么不经过。所以我们可以把经过根节点的符合点对统计出来。接着对于每一个子树再次运算。如果不用点分治的技巧,时间复杂度可能退化成\(O(n^2)\)(链)。如果对于子树重新选根,找到树的重心,就一定可以保证时间复杂度在\(O(nlogn)\)内。
具体技巧是:首先选出树的重心,将重心视为根。接着计算出每个结点的深度,以此统计答案。由于子树中可能出现重复情况,需要在子树中相应的减去一部分ans。具体实现在代码中。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e4+5;
struct Graph{
struct Edge{
int to, next, v; Graph *bel;
Edge& operator ++(){
return *this=bel->edge[next]; }
}edge[maxn*2];
int cntedge, fir[maxn];
void addedge(int x, int y, int v){
Edge &e=edge[++cntedge];
e.to=y; e.next=fir[x]; e.v=v;
fir[x]=cntedge; e.bel=this;
}
Edge& getlink(int x){ return edge[fir[x]]; }
void RESET(){ cntedge=0; memset(fir, 0, sizeof(fir)); }
}g;
int n, k, size[maxn], w[maxn], dep[maxn];
int cnt[maxn], tail;
bool done[maxn];
//获取子树大小
int getsize(int now, int par, int num){
size[now]=0; w[now]=0;
Graph::Edge e=g.getlink(now);
for (; e.to; ++e){
if (e.to==par||done[e.to]) continue;
size[now]+=getsize(e.to, now, num);
w[now]=max(w[now], size[e.to]);
}
++size[now]; w[now]=max(w[now], num-size[now]);
return size[now];
}
//获取根的位置
int getroot(int now, int par){
Graph::Edge e=g.getlink(now);
int root=now, tmp=now;
for (; e.to; ++e){
if (e.to==par||done[e.to]) continue;
tmp=getroot(e.to, now);
if (w[tmp]<w[root]) root=tmp; //mdzzle
}
return root;
}
//获取子树中结点深度,并创造深度数组
void getdep(int now, int par, int step){
Graph::Edge e=g.getlink(now);
for (; e.to; ++e)
if (e.to!=par&&!done[e.to])
getdep(e.to, now, step+e.v);
dep[now]=step;
cnt[tail++]=step;
}
//通过深度数组统计和小于等于k的数对
int getans(int k, int tail){
sort(cnt, cnt+tail);
--tail; int ans=0;
for (int l=0; l<tail; ++l){
while (cnt[l]+cnt[tail]>k&&l<tail) --tail;
ans+=tail-l;
}
return ans;
}
int solve(int now, int num){
getsize(now, 0, num); //获取当前树的子树大小
if (size[now]==1) return 0;
now=getroot(now, 0); //凭借子树大小找到重心
tail=0; //把深度数组复原
getdep(now, 0, 0); //获取每个结点的深度,构建深度数组
//获取答案,别忘记减掉重复的点对
int ans=getans(k, tail);
done[now]=true; //堵住当前点
Graph::Edge e=g.getlink(now);
for (; e.to; ++e) if (!done[e.to]){
tail=0; getdep(e.to, 0, 0);
ans-=getans(k-e.v*2, tail);
ans+=solve(e.to, size[e.to]);
}
return ans;
}
int main(){
while (~scanf("%d%d", &n, &k)&&n&&k){
int t1, t2, t3; g.RESET();
for (int i=1; i<=n; ++i) done[i]=false;
for (int i=1; i<n; ++i){
scanf("%d%d%d", &t1, &t2, &t3);
g.addedge(t1, t2, t3);
g.addedge(t2, t1, t3);
}
printf("%d\n", solve(1, n));
}
return 0;
}
poj 1741 Tree(树的点分治)的更多相关文章
- POJ 1741 Tree(树的点分治,入门题)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 21357 Accepted: 7006 Description ...
- POJ 1741 Tree 树的分治(点分治)
题目大意:给出一颗无根树和每条边的权值,求出树上两个点之间距离<=k的点的对数. 思路:树的点分治.利用递归和求树的重心来解决这类问题.由于满足题意的点对一共仅仅有两种: 1.在以该节点的子树中 ...
- poj 1741(树的点分治)
Tree Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...
- POJ 1741/1987 树的点分治
树的点分治,主要思想是每次找子树的重心,计算经过根节点的情况数,再减去点对属于同一子树的情况. #include <iostream> #include <vector> #i ...
- POJ 1741.Tree 树分治 树形dp 树上点对
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ...
- POJ 1741 Tree 树的分治
原题链接:http://poj.org/problem?id=1741 题意: 给你棵树,询问有多少点对,使得这条路径上的权值和小于K 题解: 就..大约就是树的分治 代码: #include< ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- poj 1741 Tree (树的分治)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 30928 Accepted: 10351 Descriptio ...
- POJ 1741 Tree 树形DP(分治)
链接:id=1741">http://poj.org/problem?id=1741 题意:给出一棵树,节点数为N(N<=10000),给出N-1条边的两点和权值,给出数值k,问 ...
随机推荐
- mysql多位小数字段用decimal类型
转自http://database.51cto.com/art/201005/201651.htm
- Java企业微信开发_13_异常:com.qq.weixin.mp.aes.AesException: 解密后得到的buffer非法
一.异常信息 方法:POST@ echostr是否存在 :false java.lang.IllegalArgumentException: 20 > -367029533 at java.ut ...
- BZOJ4974 大视野1708月赛 字符串大师
传送门 题目大意 给定一个字符串的每一个前缀的最短循环节长度,求符合要求的字典序最小的字符串. 题解 给定循环节最短长度就是给定了这个字符串$kmp$的$next$数组,即$X_i=i-next_i$ ...
- Nodejs文件相关操作
欢迎关注我的博客我在马路边 适用人群 本文适用于刚接触Node的小白,毕竟我也是小白,大佬请绕行. Node文件操作 在实际开发中遇到很多有关文件及文件夹的操作,比如创建.删除文件及文件夹,文件拷贝. ...
- java代码JFrame练习
总结: package com.da; import java.awt.Button; import java.awt.Color; import java.awt.FlowLayout; impor ...
- 关于openstack自动化安装的一点思考
在openstack针对具体应用的解决方案已成型之后,按照官方文档安装openstack实际上就成了一个繁琐的事情. 我有一个设想,之前实施了一点,还未成功,但是也想记录下来.最终目标:使用U盘直接部 ...
- Python模块-subprocess模块
Run()方法 >>> a = subprocess.run(['df','-h']) 文件系统 容量 已用 可用 已用% 挂载点 udev 468M 0 468M 0% /dev ...
- 配置IIS服务:无法找到该页 您正在搜索的页面可能已经删除、更名或暂时不可用。
1.配置IIS服务器时,在默认网站创建虚拟目录XXX.然后右击启动页面.aspx,“浏览” 2. 出现错误: 无法找到该页 您正在搜索的页面可能已经删除.更名或暂时不可用. ------------ ...
- JavaScript权威指南读书笔记【第一章】
第一章 JavaScript概述 前端三大技能: HTML: 描述网页内容 CSS: 描述网页样式 JavaScript: 描述网页行为 特点:动态.弱类型.适合面向对象和函数式编程的风格 语法源自J ...
- shell入门-连接符(并且、和、或者)
特殊符号:&& 说明:并且,左右两边是两条命令,左面的执行成功才会去执行右面的命令.右. 特殊符号:|| 说明:或者,左右两边是两条命令,左边的命令执行不成功,才会执行右面的命令 &a ...