• POJ1741(SummerTrainingDay08-G 树的点分治)


    Tree

    Time Limit: 1000MS   Memory Limit: 30000K
    Total Submissions: 23380   Accepted: 7748

    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

    Source

     
      1 //2017-08-09
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <algorithm>
      6 #include <vector>
      7 
      8 using namespace std;
      9 
     10 const int N = 10010;
     11 int n, k, MAX, root, cnt, answer;
     12 
     13 //链式前向星
     14 int head[N], tot;
     15 struct Edge{
     16     int next, to, w;
     17 }edge[N<<4];
     18 
     19 void add_edge(int u, int v, int w){
     20     edge[tot].w = w;
     21     edge[tot].to = v;
     22     edge[tot].next = head[u];
     23     head[u] = tot++;
     24 }
     25 
     26 int size[N];//size[i]表示以i为根的子树的大小,包括i。
     27 int maxson[N];//maxson[i]表示以i为根的子树的最大儿子的大小。
     28 int dis[N];//dis[i]表示i到根的距离。
     29 bool vis[N];//vis[i]用来标记i点是否被删除。
     30 
     31 void init(int n){
     32     answer = 0;
     33     tot = 0;
     34     memset(vis, 0, sizeof(vis));
     35     memset(head, -1, sizeof(head));
     36 }
     37 
     38 //计算出子树的大小
     39 void dfs_size(int u, int fa){
     40     size[u] = 1;
     41     maxson[u] = 0;
     42     for(int i = head[u]; ~i; i = edge[i].next){
     43         int v = edge[i].to;
     44         if(vis[v] || v == fa)continue;
     45         dfs_size(v, u);
     46         size[u] += size[v];
     47         if(size[v] > maxson[u])
     48               maxson[u] = size[v];
     49     }
     50 }
     51 
     52 //找子树的重心。最大子树最小的点即为树的重心。
     53 void dfs_root(int r, int u, int fa){
     54     if(size[r] - size[u] > maxson[u])//size[r]-size[u]为u上面的树的尺寸
     55           maxson[u] = size[r] - size[u];
     56     if(maxson[u] < MAX){
     57         MAX = maxson[u];
     58         root = u;
     59     }
     60     for(int i = head[u]; ~i; i = edge[i].next){
     61         int v = edge[i].to;
     62         if(vis[v] || v == fa)continue;
     63         dfs_root(r, v, u);
     64     }
     65 }
     66 
     67 //计算出子树中每个点距离重心的距离
     68 void dfs_dis(int u, int d, int fa){
     69     dis[cnt++] = d;
     70     for(int i = head[u]; ~i; i = edge[i].next){
     71         int v = edge[i].to;
     72         if(vis[v] || v == fa)continue;
     73         dfs_dis(v, d+edge[i].w, u);
     74     }
     75 }
     76 
     77 //计算出以u为根的子树中距离和小于k的点对数
     78 int cal(int u, int d){
     79     int ans = 0;
     80     cnt = 0;
     81     dfs_dis(u, d, 0);
     82     sort(dis, dis+cnt);
     83     for(int i = 0, j = cnt-1; i < j; i++){
     84         while(dis[i]+dis[j] > k && i < j)//双指针
     85               j--;
     86         ans += j-i;
     87     }
     88     return ans;
     89 }
     90 
     91 //分治,找到树的重心,分为经过重心的点对和不经过重心的点对。
     92 void solve(int u){
     93     MAX = n;
     94     dfs_size(u, 0);
     95     dfs_root(u, u, 0);
     96     answer += cal(root, 0);
     97     vis[root] = 1;
     98     for(int i = head[root]; ~i; i = edge[i].next){
     99         int v = edge[i].to;
    100         if(vis[v])continue;
    101         answer -= cal(v, edge[i].w);
    102         solve(v);
    103     }
    104 }
    105 
    106 int main()
    107 {
    108     //freopen("dataIn.txt", "r", stdin);
    109     while(scanf("%d%d", &n, &k)!=EOF){
    110         if(!n && !k)break;
    111         int u, v, w;
    112         init(n);
    113         for(int i = 0; i < n-1; i++){
    114             scanf("%d%d%d", &u, &v, &w);
    115             add_edge(u, v, w);
    116             add_edge(v, u, w);
    117         }
    118         solve(1);
    119         printf("%d
    ", answer);
    120     }
    121 
    122     return 0;
    123 }
  • 相关阅读:
    Eclipse 安装Activiti插件(BPMN打开工具)
    POI Excel 单元格内容类型判断并取值
    AJAX获取数据成功后的返回数据如何声明成全局变量
    java 思维导图
    java excel Workbook API
    金额 保留两位小数
    mybatis教程3(映射文件)
    mybatis教程1(基本使用)
    mybatis教程之原理剖析
    Maven教程4(私服-nexus)
  • 原文地址:https://www.cnblogs.com/Penn000/p/7327517.html
Copyright © 2020-2023  润新知