「POJ 1741」Tree

题面:

Tree

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

题意:

给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

输入格式: 每次输入n,k(如果n0&&k0停止),接着n-1行,每行3个数描述边

这道题就是一道淀粉质点分治的模板题,具体不多讲,如果不会看看这个

接下来直接上代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200001;
int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')c=='-'?f=-1,c=getchar():c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
int n,k;
int dep[N];/*从当前节点i到枚举当前树的根节点父亲的距离*/
int f[N];/*当i为根节点时最大字数大小*/
int vis[N];/*i节点是否被当根使用过*/
int siz[N];/*以i节点为根时,其子树(包括本身)的节点个数*/
int root;/*根节点*/
struct node {
    int next,to,v;
} a[N<<1];
int head[N],cnt,sum/*这棵当前递归的这棵树的大小*/;
void add(int x,int y,int c) {
    a[++cnt].to=y;
    a[cnt].next=head[x];
    a[cnt].v=c;
    head[x]=cnt;
}
void findroot(int k,int fa) {
    f[k]=0,siz[k]=1;
    for(int i=head[k]; i; i=a[i].next) {
        int v=a[i].to;
        if(vis[v]||v==fa)
            continue;
        findroot(v,k);
        siz[k]+=siz[v];
        f[k]=max(f[k],siz[v]);
    }
    f[k]=max(f[k],sum-siz[k]);
    if(f[k]<f[root])
        root=k;
}
int tot;
void finddep(int k,int fa,int l) {
    dep[++tot]=l;
    for(int i=head[k]; i; i=a[i].next) {
        int v=a[i].to;
        if(v==fa||vis[v])
            continue;
        finddep(v,k,l+a[i].v);
    }
}
int K;
int calc(int k,int L) {
    tot=0;
    finddep(k,0,L);
    sort(dep+1,dep+1+tot);
    int l=1,r=tot,ans=0;
    while(l<r){
        if(dep[l]+dep[r]<=K)
            l++,ans+=r-l+1;
        else
            r--;
    }
    return ans;
}
int js;
void devide(int k) {
    vis[k]=1;
    js+=calc(k,0);
    for(int i=head[k]; i; i=a[i].next) {
        int v=a[i].to;
        if(vis[v])
            continue;
        js-=calc(v,a[i].v);
        root=0,sum=siz[v];
        findroot(v,0);
        devide(root);
    }
}
int main() {
    int n=read(),x,y,z;
    K=read();
    while(n&&K){
        memset(head,0,sizeof(head)),cnt=0;//head
        memset(vis,0,sizeof(vis));//标记数组
        for (int i=1; i<n; i++)
            x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
        sum=f[0]=n,js=0;//总数
        findroot(1,0);
        devide(root);
        printf("%d\n",js);
        n=read(),K=read();
    }
    return 0;
}

注意初始化!!!注意初始化!!!注意初始化!!!
重要的事情说三遍

posted @ 2018-10-22 17:30  撤云  阅读(128)  评论(0编辑  收藏  举报
……