内容目录
Language:
Tree
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 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0 Sample Output 8 Source |
在漆子超的论文里有该题的详细解题报告。
在这里简单说说树链剖分中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; }