• POJ 1741 Tree 树分治


    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

    题意:

      给你一个含有n个节点的树,每条边有权值,问你有多少点对最短路径不超过k

     

    题解:

      树分治入门题

      推荐看09年ioi的论文

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const int N = 1e5+20, M = 1e2+10, mod = 1e9+7, inf = 1e9+1000;
    typedef long long ll;
    
    int n,m,root,t,ans,allnode,siz[N],K,head[N],vis[N],d[N];
    int deep[N];//路径长度//deep[0]子节点个数
    int f[N];//重心
    
    struct edg{int to,next,v;}e[N * 4];//前向星存边
    void add(int u,int v,int w) {e[t].to=v;e[t].next=head[u];e[t].v=w;head[u]=t++;}//加边
    
    //获取重心
    void getroot(int x,int fa) {
        siz[x] = 1;
        f[x] = 0;
        for(int i=head[x];i;i=e[i].next) {
            int to = e[i].to;
            if(to == fa || vis[to]) continue;
            getroot(to,x);
            siz[x] += siz[to];
            f[x] = max(f[x] , siz[to]);
        }
        f[x] = max(allnode-siz[x] , f[x]);
        if(f[x] < f[root]) root = x;
    }
    
    void getdeep(int x,int fa) {//获取子树所有节点与根的距离
        deep[++deep[0]] = d[x];
        for(int i=head[x];i;i=e[i].next) {
            int to = e[i].to;
            if(to == fa || vis[to]) continue;
            d[to] = d[x] + e[i].v;
            getdeep(to,x);
        }
    }
    int cal(int x,int now) {//计算当前以重心x的子树下,所有情况的答案
        d[x]=now;deep[0]=0;
        getdeep(x,0);
        sort(deep+1,deep+deep[0]+1);
        int all = 0;
        for(int l=1,r=deep[0];l<r;) {
            if(deep[l]+deep[r] <= K) {all += r-l;l++;}
            else r--;
        }
        return all;
    }
    
    void work(int x) {//以x为重心进行计算
        vis[x] = 1;
        ans+=cal(x,0);
        for(int i=head[x];i;i=e[i].next) {
            int to = e[i].to;
            if(vis[to]) continue;
            ans -= cal(to,e[i].v);
            allnode = siz[to];
            root=0;
            getroot(to,x);
            work(root);
        }
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&K)) {
            if(!n&&!m) break;
            memset(head,0,sizeof(head));
            memset(vis,0,sizeof(vis));
            t = 1;
            for(int i=1;i<n;i++) {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                add(a,b,c) , add(b,a,c);
            }
            root=ans=0;
            allnode=n;f[0]=inf;
            getroot(1,0);
            work(root);
            printf("%d
    ",ans);
        }
    }

     

  • 相关阅读:
    JAVA中的流-简介(二)
    JAVA中的流-简介(一)
    Java中内部类简介
    应用小练习-自定义栈
    集合知识点(二)
    集合知识点(一)
    JAVA中的正则表达式简介
    从头文件中学习sfr和sbit
    PCB中实现元器件旋转一个角度放置
    DXP中插入LOGO字体方法(2)
  • 原文地址:https://www.cnblogs.com/zxhl/p/5692688.html
Copyright © 2020-2023  润新知