POJ 1741(男人八题-Tree-点分治)

来源:互联网 发布:office for mac汉化包 编辑:程序博客网 时间:2024/06/06 05:57
Language:
Tree
Time Limit: 1000MS Memory Limit: 30000KTotal Submissions: 6982 Accepted: 2010

Description

给定一棵 N (1 N 10000) 个结点的带权(≤1000)树,定义 dist(u, v) 为 u, v 两点间的最短路径长度, 路径的长度定义为路径上所有边的权和。再给定一个 K (1 K 10 ) ,如果对于不同的两个结点 a, b ,如果满 足 dist (a, b) K ,则称 (a, b) 为合法点对。 求合法点对个数。

Input

有很多数据. 每组数据第一行为 n, k. (n<=10000) 接下来 n-1 行为 u,v,w, 表示u和v之间有一条权为w的边. 
数据以‘0 0’结尾. 

Output

对每组数据输出一行合法点对个数.

Sample Input

5 41 2 31 3 11 4 23 5 10 0

Sample Output

8

Source

LouTiancheng@POJ

在漆子超的论文里有该题的详细解题报告

在这里简单说说树链剖分中center_node的选取。

center_node为一棵子树中的一个能使其为根节点时,其的子树的最大结点数最小的的结点。

也就是使子树的max_siz最小

因为换了root,必须用b记录,防止走到子树外去。


重儿子:一个节点的儿子中siz最大的那个(hson)


#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#include<functional>#include<algorithm>using namespace std;#define MAXN (10000+10)int n,k;int edge[MAXN*2],pre[MAXN],next[MAXN*2],weight[MAXN*2],size=0;bool b[MAXN];void addedge(int u,int v,int w){edge[++size]=v;weight[size]=w;next[size]=pre[u];pre[u]=size;}int dis[MAXN],deep[MAXN],siz[MAXN],max_sub_siz[MAXN],tot;int que[MAXN],q_n;void get_center_dfs(int u,int fa){siz[u]=1;que[++q_n]=u;max_sub_siz[u]=0;for (int p=pre[u];p;p=next[p]){int &v=edge[p];if (v!=fa&&!b[v]){get_center_dfs(v,u);siz[u]+=siz[v];max_sub_siz[u]=max(max_sub_siz[u],siz[v]);}}}int get_center(int u,int fa){int minhson=n,mini=0;q_n=0;get_center_dfs(u,fa);for (int i=1;i<=q_n;i++){max_sub_siz[que[i]]=max(max_sub_siz[que[i]],q_n-siz[que[i]]);if (minhson>max_sub_siz[que[i]]){minhson=max_sub_siz[que[i]];mini=que[i];}}return mini;}void getdis(int u,int d,int fa){dis[++tot]=d;for (int p=pre[u];p;p=next[p]){int &v=edge[p];if (v!=fa&&!b[v]){getdis(v,d+weight[p],u);}}}int count_dis(int l,int r){int i=l,j=r,ans=0;sort(dis+l,dis+r+1);while (i<j){if (dis[i]+dis[j]<=k) ans+=j-(i++);else j--;}return ans;}int dfs_main(int u,int fa){int root=get_center(u,fa),ans=0;tot=0;b[root]=1;for (int p=pre[root];p;p=next[p]) //root{int &v=edge[p];if (v!=fa&&!b[v]){int l=tot+1;getdis(v,weight[p],root);ans-=count_dis(l,tot);}}dis[++tot]=0;ans+=count_dis(1,tot);for (int p=pre[root];p;p=next[p]){int &v=edge[p];if (v!=fa&&!b[v]){ans+=dfs_main(v,root);}}return ans;}int main(){//freopen("poj1741.in","r",stdin);while (scanf("%d%d",&n,&k)&&(n+k)){memset(pre,0,sizeof(pre));size=0;memset(b,0,sizeof(b));int u,v,w;for (int i=1;i<n;i++){scanf("%d%d%d",&u,&v,&w);addedge(u,v,w);addedge(v,u,w);}cout<<dfs_main(edge[1],0)<<endl;}return 0;}