zoukankan      html  css  js  c++  java
  • tree(poj 1741)

    题意:给一颗n个节点的树,每条边上有一个距离v(v<=1000)。定义d(u,v)为u到v的最小距离。给定k值,求有多少点对(u,v)使u到v的距离小于等于k。

    /*
      照着点分治模板敲了敲,有很多细节地方应该注意,不然很容易出错。
      点分治的大概就是解决树上路径中统计某些东西的一个算法,顾名思义,肯定与递归有些关系。
      简单步骤就是:①求重心 ②统计这棵树的答案 ③递归到它的子树求解
      推荐一篇博客:http://www.cnblogs.com/chty/p/5912360.html 
    */
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define N 10010
    #define inf 100000000
    using namespace std;
    int head[N],deep[N],d[N],vis[N],son[N],f[N],root,sum,ans,n,m;
    struct node{
        int to,t,pre;
    };node e[N*2];
    void add(int i,int x,int y,int z){
        e[i].to=y;
        e[i].t=z;
        e[i].pre=head[x];
        head[x]=i;
    }
    void getroot(int x,int fa){
        son[x]=1;f[x]=0;
        for(int i=head[x];i;i=e[i].pre){
            if(vis[e[i].to]||e[i].to==fa) continue;
            getroot(e[i].to,x);
            son[x]+=son[e[i].to];
            f[x]=max(f[x],son[e[i].to]);
        }
        f[x]=max(f[x],sum-son[x]);
        if(f[x]<f[root])root=x;
    }
    void getdeep(int x,int fa){//求出x的子树上的节点的深度(x深度不一定为0) 
        deep[++deep[0]]=d[x];
        for(int i=head[x];i;i=e[i].pre){
            if(vis[e[i].to]||e[i].to==fa) continue;
            d[e[i].to]=d[x]+e[i].t;
            getdeep(e[i].to,x);
        }
    }
    int cal(int x,int v){//求出x的子树上的答案,但是对于本题目多计算了两个点在同一条子树上的情况 
        d[x]=v;deep[0]=0;
        getdeep(x,0);
        sort(deep+1,deep+deep[0]+1);
        int l=1,r=deep[0],tot=0;
        while(l<r){
            if(deep[r]+deep[l]<=m) tot+=r-l,l++;
            else r--;
        }
        return tot;
    }
    void solve(int x){//求出x的子树上的答案
        ans+=cal(x,0);
        vis[x]=1;
        for(int i=head[x];i;i=e[i].pre){
            if(vis[e[i].to]) continue;
            ans-=cal(e[i].to,e[i].t);
            sum=son[e[i].to];
            root=0;
            getroot(e[i].to,0);
            solve(root);
        }
    }
    int main(){
        while(scanf("%d%d",&n,&m)){
            if(!n&&!m) break;
            ans=root=0;
            memset(head,0,sizeof(head));
            memset(vis,0,sizeof(vis));
            for(int i=1;i<n;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                add(i*2-1,x,y,z);add(i*2,y,x,z);
            }
            sum=n;f[0]=inf;
            getroot(1,0);
            solve(root);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    sql server 2008 64位连接sql 2000服务器的时候出现
    MySQL忘记密码怎么修改密码
    vs2015 行数统计
    javascript和c#aes加密方法互解
    vs2015 不能启动 iis express
    修改oracle的字符集操作方法
    PL/SQL Developer连接本地Oracle 11g 64位数据库
    CodeSmith Generator 7.0.2激活步骤
    PetaPoco利用ODP.NET Managed Driver连接Oracle
    解决Chrome插件安装时出现的“程序包无效”问题亲测可用
  • 原文地址:https://www.cnblogs.com/harden/p/6280036.html
Copyright © 2011-2022 走看看