POJ1741 Tree

Posted autoint

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1741 Tree相关的知识,希望对你有一定的参考价值。

题意

Language:
Tree
Time Limit: 1000MSMemory Limit: 30000K
Total Submissions: 32398Accepted: 10810

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

分析

点分治模板题。每次选择要处理的子树的重心,这样每个节点的处理不会超过\(O(\log n)\)次。

要路径长≤k,可以把节点放入按照距离根的距离排序,维护指针L,R,可以发现L从左到右扫描的过程中,恰好使得d[L]+d[R]≤k的R的范围是从右向左单调递减的,所以可以直接扫描处理。由于要排除同一子树内的节点之间的路径,所以要记录[L,R]与L处于同一子树内的节点的个数cnt[belong[L]]。那么L的答案就是R-L-cnt[belong[L]]。

时间复杂度\(O(n \log^2)\)

代码

值得一提的是,读入边的时候用快读会TLE,写成scanf才能AC。大概是数据有问题……

#include<iostream>
#include<cstring>
#include<algorithm>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;

co int N=1e4+1;
int n,k,s[N],Ans;
bool v[N],w[N];
int Head[N],Edge[N*2],Leng[N*2],Next[N*2],t;
int ans,pos;
int d[N],b[N],a[N],tot,cnt[N];
void dfs_find(int S,int x){
    v[x]=1,s[x]=1;
    int max_part=0;
    for(int i=Head[x];i;i=Next[i]){
        int y=Edge[i];
        if(v[y]||w[y]) continue;
        dfs_find(S,y);
        s[x]+=s[y];
        max_part=max(max_part,s[y]);
    }
    max_part=max(max_part,S-s[x]);
    if(max_part<ans) ans=max_part,pos=x;
}
void dfs(int x){
    v[x]=1;
    for(int i=Head[x];i;i=Next[i]){
        int y=Edge[i],z=Leng[i];
        if(v[y]||w[y]) continue;
        ++cnt[b[a[++tot]=y]=b[x]];
        d[y]=d[x]+z;
        dfs(y);
    }
}
bool cmp(int i,int j) {return d[i]<d[j];}
void work(int S,int x){
    memset(v,0,sizeof v);
    dfs_find(ans=S,x);
    memset(d,0,sizeof d);
    memset(cnt,0,sizeof cnt);
    memset(v,0,sizeof v);
    w[a[tot=1]=b[pos]=pos]=1;
    ++cnt[pos];
    for(int i=Head[pos];i;i=Next[i]){
        int y=Edge[i],z=Leng[i];
        if(v[y]||w[y]) continue;
        ++cnt[a[++tot]=b[y]=y];
        d[y]=z;
        dfs(y);
    }
    sort(a+1,a+tot+1,cmp);
    int l=1,r=tot;
    --cnt[b[a[1]]];
    while(l<r){
        while(d[a[l]]+d[a[r]]>k) --cnt[b[a[r--]]];
        Ans+=r-l-cnt[b[a[l]]];
        --cnt[b[a[++l]]];
    }
    int now=pos;
    for(int i=Head[now];i;i=Next[i]){
        int y=Edge[i];
        if(w[y]) continue;
        work(s[y],y);
    }
}
void add(int x,int y,int z){
    Edge[++t]=y,Leng[t]=z;
    Next[t]=Head[x],Head[x]=t;
}
void Tree(){
    t=0;
    memset(Head,0,sizeof Head);
    for(int i=1,x,y,z;i<n;++i){
//      read(x),read(y),read(z);
        scanf("%d %d %d", &x, &y, &z);
        add(x,y,z),add(y,x,z);
    }
    memset(w,0,sizeof w);
    Ans=0;
    work(n,1);
    printf("%d\n",Ans);
}
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    while(read(n)|read(k)) Tree();
    return 0;
}

以上是关于POJ1741 Tree的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1741 Tree ——点分治

Tree POJ - 1741

POJ 1741 Tree

poj1741 Tree

POJ 1741 Tree ——(树分治)

POJ 1741 Tree 树分治