zoukankan      html  css  js  c++  java
  • poj 1741 Tree

    题目大意:有一颗由n个点组成的树,问树上两点间距离小于等于k的点对有多少对
    输入:多组数据输入。每组数据第1行n,k,接下来n-1行,u,v,l表示点u与点v之间有一条长为l的边
    输出:点对个数

     

    /*
        借此题说说对点分治的认识,点分治就是将一棵树分为几部分,使得最大的一部分的点数最小,也就是找树的重心
        对于经过重心的,
        1、统计出过重心的所有点的满足条件的数目=ans1
        2、对于每棵子树,统计一遍自己内部满足条件的数目=ans2
        ans=ans1-所有的ans2
        对于不经过重心的,继续递归
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define INF 0x7fffffff
    #define maxn 10010
    struct node{int to,v,pre;}e[maxn*2];
    int n,num,k,root,sum,ans,head[maxn],f[maxn];
    int vis[maxn],son[maxn],d[maxn],dep[maxn];
    void Insert(int from,int to,int v){
        e[++num].to=to;
        e[num].v=v;
        e[num].pre=head[from];
        head[from]=num;
    }
    void getroot(int x,int fa){
        son[x]=1;f[x]=0;
        for(int i=head[x];i;i=e[i].pre){
            int to=e[i].to;
            if(to==fa||vis[to])continue;
            getroot(to,x);
            son[x]+=son[to];
            f[x]=max(f[x],son[to]);
        }
        f[x]=max(f[x],sum-son[x]);
        if(f[x]<f[root])root=x;
    }
    void getdeep(int x,int fa){
        dep[++dep[0]]=d[x];
        for(int i=head[x];i;i=e[i].pre){
            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 v){
        d[x]=v;dep[0]=0;
        getdeep(x,0);
        sort(dep+1,dep+dep[0]+1);
        int l=1,r=dep[0],sum=0;
        while(l<r){
            if(dep[l]+dep[r]<=k){sum+=r-l;l++;}
            else r--;
        }
        return sum;
    }
    void solve(int x){
        ans+=cal(x,0);
        vis[x]=1;
        for(int i=head[x];i;i=e[i].pre){
            int to=e[i].to;
            if(vis[to])continue;
            ans-=cal(to,e[i].v);
            sum=son[to];
            root=0;
            getroot(to,0);
            solve(root);
        }
    }
    int main(){
        //freopen("Cola.txt","r",stdin);
        while(1){
            ans=0,root=0,num=0;
            memset(vis,0,sizeof(vis));
            memset(head,0,sizeof(head));
            scanf("%d%d",&n,&k);
            if(n==0&&k==0)break;
            for(int i=1;i<=n-1;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                Insert(x,y,z);Insert(y,x,z);
            }
            f[0]=INF;sum=n;
            getroot(1,0);
            solve(root);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    enter事件处方方法
    vue 关于父组件无法触发子组件的事件的解决方法
    iview表格高度自适应只需要三步即可
    子组件触发父组件的方法
    组件之间的方法
    年与日时分秒各种格式 补0位的方法
    //定义一个函数,删除首个数组元素
    input标签内容改变的触发事件
    jQuery表单校验jquery.validate.js的使用
    jQuery BlockUI 实现锁屏
  • 原文地址:https://www.cnblogs.com/thmyl/p/8046001.html
Copyright © 2011-2022 走看看