POJ 1741 Tree [点分治]
Posted cytus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1741 Tree [点分治]相关的知识,希望对你有一定的参考价值。
Tree
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 30475 | Accepted: 10232 |
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.
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.
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
分析:
点分治的入门题,不过也还是有点难度的。
首先我们先找出树的重心,然后把它作为根节点算出它的子树中每一个点到它的距离,然后用一种类似二分的方法求出答案,但是这样求出的答案是有问题的,因为这样求出来的两点的距离可能会重复经过一条边两次,所以需要进行容斥。所以就递归调用,每次统计完答案以后减去子树可以得到的答案,然后再对子树进行同样的操作。
讲的比较抽象,可以结合代码理解。
Code:
//It is made by HolseLee on 17th Oct 2018 //POJ1741 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=5e4+7; const int inf=1e9+7; int n,K,dis[N],sim[N],mxson[N],head[N],cnte,root,S,MX,summer; long long ans; bool vis[N]; struct Edge { int to,nxt,val; }e[N<<1]; inline int read() { char ch=getchar(); int num=0; bool flag=false; while( ch<‘0‘ || ch>‘9‘ ) { if( ch==‘-‘ ) flag=false; ch=getchar(); } while( ch>=‘0‘ && ch<=‘9‘ ) { num=num*10+ch-‘0‘; ch=getchar(); } return flag ? -num : num; } void print(int x) { if( x>9 ) print(x/10); putchar(x%10+‘0‘); } inline void add(int x,int y,int z) { e[++cnte].to=y; e[cnte].val=z; e[cnte].nxt=head[x]; head[x]=cnte; } void getroot(int x,int fa) { sim[x]=1, mxson[x]=0; for(int i=head[x],y; i; i=e[i].nxt) { y=e[i].to; if( y==fa || vis[x] ) continue; getroot(y,x); sim[x]+=sim[y]; mxson[x]=max(mxson[x],sim[y]); } mxson[x]=max(mxson[x],S-sim[x]); if( mxson[x]<MX ) { MX=mxson[x]; root=x; } } void getdis(int x,int fa,int dist) { dis[++summer]=dist; for(int i=head[x],y; i; i=e[i].nxt) { y=e[i].to; if( y==fa || vis[y] ) continue; getdis(y,x,dist+e[i].val); } } inline int work(int x,int len) { summer=0; memset(dis,0,sizeof(dis)); getdis(x,0,len); sort(dis+1,dis+summer+1); int l=1, r=summer, ret=0; while( l<r ) { if( dis[l]+dis[r]<=K ) { ret+=(r-l); l++; } else r--; } return ret; } void divide(int x) { ans+=work(x,0); vis[x]=1; for(int i=head[x],y; i; i=e[i].nxt) { y=e[i].to; if( vis[y] ) continue; ans-=work(y,e[i].val); S=sim[y]; root=0; MX=inf; getroot(y,0); divide(y); } } int main() { while( 1 ) { n=read(), K=read(); if( !n && !K ) break; int x,y,z; cnte=ans=0; for(int i=1; i<=n; ++i) head[i]=0; for(int i=1; i<n; ++i) { x=read(); y=read(); z=read(); add(x,y,z); add(y,x,z); } memset(vis,0,sizeof(vis)); MX=inf; S=n; getroot(1,0); divide(root); print(ans); putchar(‘ ‘); } return 0; }
以上是关于POJ 1741 Tree [点分治]的主要内容,如果未能解决你的问题,请参考以下文章