poj 1741 Tree(点分治)
2016-02-12 12:36
323 查看
Tree
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
Sample Output
Source
LouTiancheng@POJ
【思路】
设i到当前root的距离为d[i],i属于belong[i]->belong[i]为当前root的儿子且i在belong[i]为根的树中。设Sum{E}为满足条件E的点对数。
情况分为两种:
1) 经过根节点
2) 不经过根节点,在根节点的一颗子树中。
其中2)可以递归求解。
对于1)我们要求的是Sum{d[i]+d[j]<=k && belong[i]!=belong[j]},即为
Sum{d[i]+d[j]<=k} - Sum{ d[i]+d[j]<=k && belong[i]==belong[j]}
前后两项都可以转化为求一个序列a中满足d[a[i]]+d[a[j]]<=k的点对数。
先将a按照d值排序,基于单调性,我们可以给出一个O(n)的统计方法。于是问题得到解决。
总的时间复杂度为O(nlog2n)
【代码】
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 15548 | Accepted: 5054 |
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
【思路】
设i到当前root的距离为d[i],i属于belong[i]->belong[i]为当前root的儿子且i在belong[i]为根的树中。设Sum{E}为满足条件E的点对数。
情况分为两种:
1) 经过根节点
2) 不经过根节点,在根节点的一颗子树中。
其中2)可以递归求解。
对于1)我们要求的是Sum{d[i]+d[j]<=k && belong[i]!=belong[j]},即为
Sum{d[i]+d[j]<=k} - Sum{ d[i]+d[j]<=k && belong[i]==belong[j]}
前后两项都可以转化为求一个序列a中满足d[a[i]]+d[a[j]]<=k的点对数。
先将a按照d值排序,基于单调性,我们可以给出一个O(n)的统计方法。于是问题得到解决。
总的时间复杂度为O(nlog2n)
【代码】
#include<cstdio> #include<vector> #include<cstring> #include<algorithm> using namespace std; const int N = 10000+10; const int INF = 1e9; struct Edge{ int u,v,w; Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}; }; int n,K,l1,l2,tl,ans; int siz ,d ,list ,f ,can ; vector<Edge> es; vector<int> g ; void adde(int u,int v,int w) { es.push_back(Edge(u,v,w)); int m=es.size(); g[u].push_back(m-1); } void init() { ans=0; es.clear(); memset(can,1,sizeof(can)); for(int i=0;i<=n;i++) g[i].clear(); } void dfs1(int u,int fa) { siz[u]=1; list[++tl]=u; for(int i=0;i<g[u].size();i++) { int v=es[g[u][i]].v; if(v!=fa && can[v]) { dfs1(v,u); f[v]=u; siz[u]+=siz[v]; } } } int getroot(int u,int fa) { //寻找u子树重心 int pos,mn=INF; tl=0; dfs1(u,fa); for(int i=1;i<=tl;i++) { int y=list[i],d=0; for(int j=0;j<g[y].size();j++) { int v=es[g[y][j]].v; if(v!=f[y] && can[v]) d=max(d,siz[v]); } if(y!=u) d=max(d,siz[u]-siz[y]); //上方 if(d<mn) mn=d , pos=y; //使大子结点数最小 } return pos; } void dfs2(int u,int fa,int dis) { list[++l1]=u; d[u]=dis; for(int i=0;i<g[u].size();i++) { int v=es[g[u][i]].v; if(v!=fa && can[v]) dfs2(v,u,dis+es[g[u][i]].w); } } int getans(int* a,int l,int r) { int res=0,j=r; for(int i=l;i<=r;i++) { while(d[a[i]]+d[a[j]]>K && j>i) j--; res+=j-i; if(i==j) break; } return res; } bool cmp(const int& x,const int& y) { return d[x]<d[y]; } void solve(int u,int fa) { int root=getroot(u,fa); l1=l2=0; for(int i=0;i<g[root].size();i++) { //统计 d[i]+d[j]<=K && belong[i]==belong[j] int v=es[g[root][i]].v; if(can[v]) { l2=l1; dfs2(v,root,es[g[root][i]].w); //insert[以v为根的子树] sort(list+l2+1,list+l1+1,cmp); ans-=getans(list,l2+1,l1); } } list[++l1]=root; d[root]=can[root]=0; sort(list+1,list+l1+1,cmp); ans+=getans(list,1,l1); //统计d[i]+d[j]<=K for(int i=0;i<g[root].size();i++) { //递归<-分治 int v=es[g[root][i]].v; if(v!=fa && can[v]) solve(v,root); } } int main() { while(scanf("%d%d",&n,&K)==2 && (n&&K)) { int u,v,w; init(); for(int i=0;i<n-1;i++) { scanf("%d%d%d",&u,&v,&w); adde(u,v,w) , adde(v,u,w); } solve(1,-1); printf("%d\n",ans); } return 0; }
相关文章推荐
- T-SQL 公用表表达式(CTE)
- 223. Rectangle Area LeetCode
- 微软公布2月Win10/Win8.1/Win7补丁更新详情 共包含13项安全更新
- POJ 2601 Simple calculations(水~)
- SQL 操作结果集 -并集、差集、交集、结果集排序
- SQL语句 - 嵌套查询
- 疑难杂症 - SQL语句整理
- spring(AOP)案例:异常处理
- SQL查询 - 表连接
- SQL语句 - 数据操作
- Shell排序的递增序列
- SQL语句 - 基本查询
- 蓝桥杯 算法训练 区间K大数查询 冒泡法排序重温
- 219. Contains Duplicate II LeetCode
- 源代码参阅之java.util.array
- Android样式的开发:Layer-list篇
- SQL Server 事务语法
- 190. Reverse Bits LeetCode
- 跟着猫哥学Golang 15 - goroutine
- unity