【POJ 1741】Tree (树上点分治)
2016-08-05 19:04
423 查看
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 Source LouTiancheng@POJ |
[Discuss]
Home Page
Go
Back
To top
【题解】【树上点分治】
【借鉴黄学长的说法:点分治 对于一条树路径 只有经过或不经过一个点的情况,对于不经过的情况 把一棵树按这个点拆成好几棵分治就行了。考虑经过这个点的情况,对于这题,可以对这个点延伸出的几棵子树各做一次dfs,记录子树中出现的距离值,对于一棵树的距离值数组,把它排序求一次ans1,再对每棵子树分别求一个自己对自己的ans2,ans1-Σans2即为最后的ans】
【我们知道一条路径要么过根结点,要么在一棵子树中,这启发了我们可以使用分治算法。】
【路径在子树中的情况只需递归处理即可,我们只需分析如何处理路径过根结点的情况。】
【dep[i]表示点i到根结点的路径长度,cal(i)=X(X为根结点的某个儿子,且结点i在以X为根的子树内)】
【所以,我们要找的就是:dep[i]+dep[j]<=k且cal(i)≠cal(j)的(i,j)数量,即:ans=(i,j)[dep[i]+dep[j]<=k]-(i,j)[cal(i)=cal(j)]】
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[200010],nxt[200010],p[200010],v[200010],tot; int f[200010],son[200010],dep[200010],vis[200010]; int n,k,d[200010],root,ans,sum; inline void clear() { tot=-1; memset(p,-1,sizeof(p)); memset(nxt,-1,sizeof(nxt)); memset(vis,0,sizeof(vis)); } inline void add(int x,int y,int val) { tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot; v[tot]=val; tot++; a[tot]=x; nxt[tot]=p[y]; p[y]=tot; v[tot]=val; } void getroot(int x,int fa) { son[x]=1; f[x]=0; int u=p[x]; while(u!=-1) { if(vis[a[u]]||a[u]==fa) {u=nxt[u]; continue;} getroot(a[u],x); son[x]+=son[a[u]]; f[x]=max(f[x],son[a[u]]); u=nxt[u]; } f[x]=max(f[x],sum-son[x]); if(f[x]<f[root]) root=x; } void getdeep(int x,int fa) { dep[++dep[0]]=d[x]; int u=p[x]; while(u!=-1) { if(vis[a[u]]||a[u]==fa) {u=nxt[u]; continue;} d[a[u]]=d[x]+v[u]; getdeep(a[u],x); u=nxt[u]; } } inline int cal(int x,int now) { d[x]=now; dep[0]=0; getdeep(x,0); sort(dep+1,dep+dep[0]+1); int l=1,r=dep[0],t=0; while(l<r) if(dep[l]+dep[r]<=k) t+=(r-l),l++; else r--; return t; } void work(int x) { ans+=cal(x,0); vis[x]=1; int u=p[x]; while(u!=-1) { if(vis[a[u]]) {u=nxt[u]; continue; } ans-=cal(a[u],v[u]); sum=son[a[u]]; root=0; getroot(a[u],root); work(root); } } int main() { int i,j; while(1) { scanf("%d%d",&n,&k); if(!n&&!k) return 0; clear(); for(i=1;i<n;++i) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); } sum=n; f[0]=1000000000; ans=0; getroot(1,0); work(root); printf("%d\n",ans); } return 0; }
相关文章推荐
- poj 1741 Tree 树上的分治
- [poj 1741] Tree 树上点分治
- POJ 1741 Tree(树上的点分治)
- 解题报告:POJ1741 Tree 树上点分治(经典好题)
- POJ1741-树的分治&树的重心&树上的路径问题-Tree
- poj 1741 Tree 分治在树上应用
- poj1741 Tree (求树上任意两点之间权值和小于k的个数)(树分治)
- POJ 1741 Tree(树上分治)
- POJ 1741 Tree [树上点分治]
- POJ 1741 Tree 树上分治
- POJ1741——Tree(树上分治,树的重心)
- POJ1741 Tree (树上点分治/treap+启发式合并)
- poj 1741 Tree 树上的分治+求树的重心
- POJ 1741 Tree (树上点分治)(楼教主男人八题之一)
- POJ-1741 TREE 点分治 树上问题
- POJ-1741 Tree (树上点分治)
- POJ-1741-Tree (点分治)
- POJ 1741 Tree 树分治
- poj 1741 Tree(树的分治)
- POJ - 1741 Tree 【树的点分治模板题】