POJ1741--Tree (树的点分治) 求树上距离小于等于k的点对数

时间:2022-12-28 15:20:42
Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 12276   Accepted: 3886

Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
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

The 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

For each test case output the answer on a single line.

Sample Input

5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0

Sample Output

8

题意:求树上距离小于等于k的点对数。。

我是用 点的分治做的,,据说还可以用启发式合并做,,附上链接http://blog.csdn.net/asdfgh0308/article/details/39845489。。挖个坑。

定义树的重心 s 为 删除s点后的 最大子树的点数 小于n/2。  那么对于任意满足条件的点对 有两种情况,,

其路径 1要么经过s  2要么不经过s。。

对于1 我们只需要 求出 以s为根的子树的点到s的距离即可。。

对于2  可以递归处理 分解为 多个1。。然后就可以求出来了。。

复杂度为nlogn*logn

 #include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const double eps = 1e-;
const int maxn = 1e4+;
struct Edge
{
int to, len;
Edge (int _x, int _len)
{
to = _x;
len = _len;
}
};
vector<Edge>G[maxn << ];
int siz[maxn];
bool vis[maxn];
void Get_size(int root, int father)
{
siz[root] = ;
for (int i = ; i < G[root].size(); i++)
{
int v = G[root][i].to;
if (v == father || vis[v] == true)
continue;
Get_size(v, root);
siz[root] += siz[v];
}
}
typedef pair<int,int>pii;
pii FindGravity(int root, int father, int t)
{
pii res = make_pair(inf, -);
int m = , sum = ;
for (int i = ; i < G[root].size(); i++)
{
int v = G[root][i].to;
if (v == father || vis[v] == true)
continue;
res = min(res, FindGravity(v, root, t));
m = max(m, siz[v]);
sum += siz[v];
}
m = max(m, t-sum);
res = min(res, make_pair(m, root));
return res;
}
void Get_len(int root, int father, int d, vector<int>&len)
{
len.push_back(d);
for (int i = ; i < G[root].size(); i++)
{
int v = G[root][i].to;
if (v == father || vis[v] == true)
continue;
Get_len(v, root, d+G[root][i].len, len);
}
}
int K;
int cnt_pair(vector<int>&ds)
{
int res = ;
sort (ds.begin(), ds.end());
int j = ds.size() - ;
for (int i = ; i < ds.size(); i++)
{
while (j > i && ds[i] + ds[j] > K)
{
j--;
}
res += (j > i ? j - i : );
}
return res;
}
int solve(int root)
{
int ans = ;
Get_size(root, -);
int s = FindGravity(root, -, siz[root]).second;
if (s == -)
return ;
vis[s] = true;
for (int i = ; i < G[s].size(); i++)
{
int v = G[s][i].to;
if (vis[v] == true)
continue;
ans += solve(v);
}
vector<int>ds;
ds.push_back();
for (int i = ; i < G[s].size(); i++)
{
int v = G[s][i].to;
if (vis[v] == true)
continue;
vector<int>rds;
Get_len(v, s, G[s][i].len, rds);
ans -= cnt_pair(rds);
ds.insert(ds.end(), rds.begin(), rds.end());
}
ans += cnt_pair(ds);
vis[s] = false;
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int n;
while ( scanf ("%d%d", &n, &K), n && K)
{
int u, v, c;
for (int i = ; i <= n; i++)
G[i].clear();
for (int i = ; i < n-; i++)
{
scanf ("%d%d%d", &u, &v, &c);
G[u].push_back(Edge(v,c));
G[v].push_back(Edge(u,c));
}
printf("%d\n", solve(n/+));
}
return ;
}

②第二种姿势,,200ms左右

 #include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const double eps = 1e-;
const int maxn = 1e4+;
struct Edge
{
int to, len, next;
}e[maxn << ];
int head[maxn], tot, N, K;
void add_edge(int u, int v, int c)
{
e[tot].to = v;
e[tot].len = c;
e[tot].next = head[u];
head[u] = tot++;
}
int siz[maxn],Mtree[maxn]; // Mtree为最大子树的大小 siz为子树的大小
bool vis[maxn];
int center;
void FindGravity(int u, int father, int cnt) // 查找重心 center
{
siz[u] = ;
Mtree[u] = ;
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (v == father || vis[v] == true)
continue;
FindGravity(v, u, cnt);
siz[u] += siz[v];
Mtree[u] = max(Mtree[u], siz[v]);
}
Mtree[u] = max(cnt - siz[u], Mtree[u]);
if (Mtree[center] > Mtree[u])
center = u;
}
int S[maxn], dep[maxn], top;
void Get_len(int u, int father, int d)
{
S[top++] = d;
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (vis[v] == true || v == father)
continue;
// dep[v] = dep[u] + e[i].len;
Get_len(v, u, d+e[i].len);
}
}
int Get_cnt(int u, int d)
{
int res = ;
top = ;
//dep[u] = d;
Get_len(u, , d);
sort (S, S+top);
int j = top - ;
for (int i = ; i < top; i++)
{
while (j > i && S[i] + S[j] > K)
j--;
res += (j > i ? j-i : );
}
return res;
}
int ans;
void solve(int r)
{
vis[r] = true;
ans += Get_cnt(r, );
for (int i = head[r]; ~i; i = e[i].next)
{
int v = e[i].to;
if (vis[v] == true)
continue;
ans -= Get_cnt(v, e[i].len);
center = ;
FindGravity(v, r, siz[v]);
solve(center);
}
}
void init()
{
tot = ;
Mtree[] = N;
memset(head, -, sizeof(head));
memset(vis, false, sizeof(vis));
center = ;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
while (scanf ("%d%d", &N,&K), N && K)
{
init();
int u, v, c;
for (int i = ; i < N-; i++)
{
scanf ("%d%d%d", &u, &v, &c);
add_edge(u, v, c);
add_edge(v, u, c);
}
ans = ;
FindGravity(N/+, -, N);
solve(center);
printf("%d\n", ans);
}
return ;
}

POJ1741--Tree (树的点分治) 求树上距离小于等于k的点对数的更多相关文章

  1. POJ1741——Tree&lpar;树的点分治&rpar;

    1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...

  2. poj1741 树上距离小于等于k的对数 点分治 入门题

    #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm& ...

  3. Codeforces 161&period;D&period; Distance in Tree-树分治&lpar;点分治,不容斥版&rpar;-树上距离为K的点对数量-蜜汁TLE &lpar;VK Cup 2012 Round 1&rpar;

    D. Distance in Tree time limit per test 3 seconds memory limit per test 512 megabytes input standard ...

  4. POJ1741 Tree 树分治模板

    http://poj.org/problem?id=1741   题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数.   dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...

  5. POJ 1741 Tree&lpar;树的点分治,入门题&rpar;

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description ...

  6. POJ 1741 Tree 求树上路径小于k的点对个数&rpar;

                                                                                                 POJ 174 ...

  7. 洛谷 P3806 【模板】点分治1-树分治&lpar;点分治,容斥版&rpar; 模板题-树上距离为k的点对是否存在

    P3806 [模板]点分治1 题目背景 感谢hzwer的点分治互测. 题目描述 给定一棵有n个点的树 询问树上距离为k的点对是否存在. 输入格式 n,m 接下来n-1条边a,b,c描述a到b有一条长度 ...

  8. P3806 离线多次询问 树上距离为K的点对是否存在 点分治

    询问树上距离为k的点对是否存在 直接n^2暴力处理点对 桶排记录 可以过 #include<cstdio> #include<cstring> #include<algo ...

  9. 【点分治】【路径小于等于k的条数】【路径恰好等于k是否存在】

    POJ1741:Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 29574   Accepted: 9915 Des ...

随机推荐

  1. consul模板的说明2

    保证模板的正常执行 使用||true $ consul-template -template "in.ctmpl:out.file:service nginx restart || true ...

  2. js用户修改密码功能模块

    ;(function(){ var ajaxSub = false, showError = function(msg){ if(msg){ $('#er_txt').html(msg).show() ...

  3. ADV数字的剪切

    #include <iostream> using namespace std; #define SIZE 9 #define MAXLEN 6 int data[SIZE][MAXLEN ...

  4. Windows 7 封装与定制不完全教程

    Windows 7 封装与定制不完全教程 从定制Win7母盘到封装详细教程 手把手教你定制WIN7小母盘 Windows 7 封装与定制不完全教程 [教程] Windows 7 封装与定制不完全教程( ...

  5. Python中re模块的使用

    #table-1 thead,#table-1 tr { border-top-width: 1px; border-top-style: solid; border-top-color: rgb(2 ...

  6. 痞子衡嵌入式:第一本Git命令教程(1)- 准备&lpar;init&sol;config&sol;&period;gitignore&rpar;

    今天是Git系列课程第一课,痞子衡给大家要讲的是创建仓库的准备工作. 1.建仓库git init 第一步是创建一个空仓库,这是一切操作的前提. // 打开git bash命令行,切换到指定目录下 ja ...

  7. 将 numeric 转换为数据类型 numeric 时出现算术溢出错误

    保存数据时控制台报错: Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: 将 numeric 转换为数据类型 numeric 时出 ...

  8. Android插件化初识

    含义:可以简单理解为将一个app分为多个小的app,其中有一个为宿主app. 解决的主要问题:代码加载.资源加载. 插件的方式:apk安装,apk不安装,dex包 插件化的优点: 1) 模块解耦,应用 ...

  9. 一图总结C&plus;&plus;中关于指针的那些事

    指向对象的指针.指向数据成员的指针,指向成员函数的指针: 数组即指针,数组的指针,指针数组: 指向函数的指针,指向类的成员函数的指针,指针作为函数參数,指针函数: 指针的指针,指向数组的指针:常指针. ...

  10. iOS开发之指定UIView的某几个角为圆角

    我们知道, 如果需要将UIView的4个角全部都为圆角,做法相当简单,只需设置其Layer的cornerRadius属性即可(项目需要使用QuartzCore框架).而若要指定某几个角(小于4)为圆角 ...