zoukankan      html  css  js  c++  java
  • POJ-1741 Tree 【点分治】

    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的路径个数,如果暴力枚举对于1e5个结点肯定是要超时的。
    这题能用点分治的原因是:对于某个点,所有的路径的要么经过它,要么不经过,因此我们只用处理经过当前节点的路径,因此可以基于点来分治。
    点分治算法大致是:
    1.无根树转化为有根树
      找到树的重心(重心即以该点为根其子树中拥有最大结点数的那颗的子树是最小的)作为根结点,保证了树的层数最小。

    2.递归处理根的子树

    Code:
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<vector>
     5 #include<cstring>
     6 using namespace std;
     7 #define INF 0x3f3f3f3f
     8 #define M(a, b) memset(a, b, sizeof(a))
     9 const int maxn = 1e5 + 5;
    10 int n, k, root, sum, ans, d[maxn], deep[maxn], son[maxn], f[maxn];
    11 bool vis[maxn];
    12 struct node {
    13     int to, w;
    14 };
    15 vector<node> G[maxn*2];
    16 
    17 void getroot(int x, int fa) {
    18     son[x] = 1; f[x] = 0;
    19     for (int i = 0; i < G[x].size(); ++i) {
    20         int v = G[x][i].to;
    21         if (v == fa || vis[v]) continue;
    22         getroot(v, x);
    23         son[x] += son[v];
    24         f[x] = max(f[x], son[v]);
    25     }
    26     f[x] = max(f[x], sum-son[x]);
    27     if (f[x] < f[root]) root = x;
    28 }
    29 
    30 void getdeep(int x, int fa) {
    31     deep[++deep[0]] = d[x];
    32     for (int i = 0; i < G[x].size(); ++i) {
    33         int v = G[x][i].to;
    34         if (v == fa || vis[v]) continue;
    35         d[v] = d[x] + G[x][i].w;
    36         getdeep(v, x);
    37     }
    38 }
    39 
    40 int cal(int x, int now) {
    41     int temp = 0, l, r;
    42     d[x] = now, deep[0] = 0;
    43     getdeep(x, 0);
    44     sort(deep+1, deep+1+deep[0]);
    45     l = 1, r = deep[0];
    46     while (l < r) {
    47         if (deep[l]+deep[r] <= k) {temp += r-l; l++;}
    48         else r--;
    49     }
    50     return temp;
    51 }
    52 
    53 void work(int x) {
    54     ans += cal(x, 0);
    55     vis[x] = 1;
    56     for (int i = 0; i < G[x].size(); ++i) {
    57         int v = G[x][i].to;
    58         if (vis[v]) continue;
    59         ans -= cal(v, G[x][i].w);
    60         sum = son[v];
    61         root = 0;
    62         getroot(v, 0);
    63         work(root);
    64     }
    65 }
    66 
    67 int main() {
    68     ios::sync_with_stdio(false);
    69     while(cin >> n >> k, n || k) {
    70         memset(vis, 0, sizeof(vis));
    71         int a, b, c;
    72         for (int i = 1; i < n; ++i) {
    73             cin >> a >> b >> c;
    74             G[a].push_back(node{b, c});
    75             G[b].push_back(node{a, c});
    76         }
    77         root = 0; ans = 0; 
    78         sum = n; f[0] = INF;
    79         getroot(1, 0);
    80         work(root);
    81         cout << ans << endl;
    82         for (int i = 0; i <= n; ++i) G[i].clear();
    83     } 
    84 
    85     return 0;
    86 }
  • 相关阅读:
    单线程写的下载器
    java反射详解
    查找替换文本文件内容
    设计模式工厂模式
    java写的多项式乘法
    java中类的生命周期
    java写的回溯法求迷宫问题
    MVC:如何使用站点地图
    WPF: RoutedEvent
    Silverlight 如何:指定和检索自定义初始化参数
  • 原文地址:https://www.cnblogs.com/robin1998/p/6536598.html
Copyright © 2011-2022 走看看