poj 1741 Tree(点分治)
| Time Limit: 1000MS | Memory Limit: 30000K | |
| Total Submissions: 15548 | Accepted: 5054 |
Description
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
Input
input contains several test cases. The first line of each test case
contains two integers n, k. (n<=10000) The following n-1 lines each
contains three integers u,v,l, which means there is an edge between node
u and v of length l.
The last test case is followed by two zeros.
Output
Sample Input
5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0
Sample Output
8
Source
【思路】
设i到当前root的距离为d[i],i属于belong[i]->belong[i]为当前root的儿子且i在belong[i]为根的树中。设Sum{E}为满足条件E的点对数。
情况分为两种:
1) 经过根节点
2) 不经过根节点,在根节点的一颗子树中。
其中2)可以递归求解。
对于1)我们要求的是Sum{d[i]+d[j]<=k && belong[i]!=belong[j]},即为
Sum{d[i]+d[j]<=k} - Sum{ d[i]+d[j]<=k && belong[i]==belong[j]}
前后两项都可以转化为求一个序列a中满足d[a[i]]+d[a[j]]<=k的点对数。
先将a按照d值排序,基于单调性,我们可以给出一个O(n)的统计方法。于是问题得到解决。
总的时间复杂度为O(nlog2n)
【代码】
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std; const int N = +;
const int INF = 1e9; struct Edge{
int u,v,w;
Edge(int u=,int v=,int w=):u(u),v(v),w(w){};
};
int n,K,l1,l2,tl,ans;
int siz[N],d[N],list[N],f[N],can[N];
vector<Edge> es;
vector<int> g[N];
void adde(int u,int v,int w) {
es.push_back(Edge(u,v,w));
int m=es.size(); g[u].push_back(m-);
} void init() {
ans=; es.clear();
memset(can,,sizeof(can));
for(int i=;i<=n;i++) g[i].clear();
}
void dfs1(int u,int fa) {
siz[u]=;
list[++tl]=u;
for(int i=;i<g[u].size();i++) {
int v=es[g[u][i]].v;
if(v!=fa && can[v]) {
dfs1(v,u);
f[v]=u; siz[u]+=siz[v];
}
}
}
int getroot(int u,int fa) { //寻找u子树重心
int pos,mn=INF;
tl=;
dfs1(u,fa);
for(int i=;i<=tl;i++) {
int y=list[i],d=;
for(int j=;j<g[y].size();j++) {
int v=es[g[y][j]].v;
if(v!=f[y] && can[v]) d=max(d,siz[v]);
}
if(y!=u) d=max(d,siz[u]-siz[y]); //上方
if(d<mn) mn=d , pos=y; //使大子结点数最小
}
return pos;
}
void dfs2(int u,int fa,int dis) {
list[++l1]=u; d[u]=dis;
for(int i=;i<g[u].size();i++) {
int v=es[g[u][i]].v;
if(v!=fa && can[v]) dfs2(v,u,dis+es[g[u][i]].w);
}
}
int getans(int* a,int l,int r) {
int res=,j=r;
for(int i=l;i<=r;i++) {
while(d[a[i]]+d[a[j]]>K && j>i) j--;
res+=j-i; if(i==j) break;
}
return res;
}
bool cmp(const int& x,const int& y) { return d[x]<d[y]; }
void solve(int u,int fa) {
int root=getroot(u,fa);
l1=l2=;
for(int i=;i<g[root].size();i++) { //统计 d[i]+d[j]<=K && belong[i]==belong[j]
int v=es[g[root][i]].v;
if(can[v]) {
l2=l1;
dfs2(v,root,es[g[root][i]].w); //insert[以v为根的子树]
sort(list+l2+,list+l1+,cmp);
ans-=getans(list,l2+,l1);
}
}
list[++l1]=root; d[root]=can[root]=;
sort(list+,list+l1+,cmp);
ans+=getans(list,,l1); //统计d[i]+d[j]<=K
for(int i=;i<g[root].size();i++) { //递归<-分治
int v=es[g[root][i]].v;
if(v!=fa && can[v]) solve(v,root);
}
} int main() {
while(scanf("%d%d",&n,&K)== && (n&&K)) {
int u,v,w;
init();
for(int i=;i<n-;i++) {
scanf("%d%d%d",&u,&v,&w);
adde(u,v,w) , adde(v,u,w);
}
solve(,-);
printf("%d\n",ans);
}
return ;
}
poj 1741 Tree(点分治)的更多相关文章
- POJ 1741.Tree 树分治 树形dp 树上点对
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- [bzoj 1468][poj 1741]Tree [点分治]
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- POJ 1741 Tree(点分治点对<=k)
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- POJ 1741 Tree ——点分治
[题目分析] 这貌似是做过第三道以Tree命名的题目了. 听说树分治的代码都很长,一直吓得不敢写,有生之年终于切掉这题. 点分治模板题目.自己YY了好久才写出来. 然后1A了,开心o(* ̄▽ ̄*)ブ ...
- [poj 1741]Tree 点分治
题意 求树上距离不超过k的点对数,边权<=1000 题解 点分治. 点分治的思想就是取一个树的重心,这种路径只有两种情况,就是经过和不经过这个重心,如果不经过重心就把树剖开递归处 ...
- POJ - 1741 - Tree - 点分治 模板
POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...
- poj 1741 Tree(树的点分治)
poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...
- POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量
POJ 1741. Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 34141 Accepted: 11420 ...
- POJ 1741 Tree 求树上路径小于k的点对个数)
POJ 174 ...
随机推荐
- office安装不了 “windows installer 服务不能更新一个或多个受保护的windows文件”
出现这种情况可能是系统中某些文件缺失了,一般发生于安装GHOST版或做过精简的系统 打开C:\WINDOWS\msagent 看看文件夹中内容是不是如下图所示: 再打开C:\Program Files ...
- Nagios Apache报Internal Server Error错误的解决方法
今天配置Nagios的时候遇到了一些麻烦,前面的步骤都一切顺利,nagios运行后,可以看到nagios的主页,但点击左边的菜单时总是提示Internal Server Error错误.错误如下: v ...
- [Ruby on Rails系列]1、开发环境准备:Vmware和Linux的安装
Ruby on Rails是一个采用Ruby语言的遵循MVC模式的Web开发框架.使用RoR会得到更加快速爽快的Web开发体验.相比于Java EE,该框架使Web开发的速度和效率变得更加轻快和敏捷. ...
- 压缩/解压 zip 时遇到 java.lang.IllegalArgumentException: MALFORMED
因为zip文件名为中文,或者压缩内容有中文 解决方法: 错误详情: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinde ...
- [itint5]两数积全为1
http://www.itint5.com/oj/#18 这一题,首先如果直接去算的话,很容易就超出int或者long的表示范围了.那么要利用%的性质,(num * 10 + 1) % a = 10 ...
- Nginx、LVS及HAProxy负载均衡软件的优缺点详解
http://www.csdn.net/article/2014-07-24/2820837
- utf-8转换为ansi和修改文件名的批处理(可解决source insight中文注释乱码问题)
source insight中文乱码有两个原因,一个是source insight的设置不正确.另外一个原因是源文件是utf-8格式的. 最近在工作中用source insight 查看jsp文件.j ...
- WinAPI——Windows 消息
消息 值 注释 WM_NULL $0000 WM_CREATE $0001 WM_DESTROY $0002 WM_MOVE $0003 WM_SIZE $0005 WM_AC ...
- COM, COM+ and .NET 的区别
所有的优秀程序员都会尽自己的最大努力去使自己所写的程序具有更好的可重用性,因为它可以让你快速地写出更加健壮和可升级性的程序. 有两种使代码重用的选择: 1.白盒:最简单的一种,就是把你的程序片拷贝到另 ...
- ubuntu查看命令
以非root用户更新系统 sudo: sudo是linux系统管理指令,是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具,如halt,reboot,su等等.这样不仅减少了root用 ...