TreeDescription
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 0Sample Output
8Source
【题意】
求树上两点间距离小等于K的方案数 (n<=10000)
【分析】
经典的点分治问题。
搞笑的我知道怎么做都纠集好久,纠结症怎么破。
每层求重心方法分治是nlogn的。
具体是,每次都只算lca为根的点对。
设dis[x]为x节点到根的距离,那么我们求dis[x]+dis[y]<=k的方案数,并且x和y要在同子树上。
先不考虑在不同子树上,直接求dis[x]+dis[y]<=k可以排序一次然后for一遍动态累加,然后再把同一棵子树上的方案数剪掉。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 10010 10 #define INF 0xfffffff 11 12 struct node 13 { 14 int x,y,c,next; 15 }t[Maxn*2];int len; 16 int first[Maxn]; 17 int n,k; 18 19 int mymax(int x,int y) {return x>y?x:y;} 20 21 void ins(int x,int y,int c) 22 { 23 t[++len].x=x;t[len].y=y;t[len].c=c; 24 t[len].next=first[x];first[x]=len; 25 } 26 int rt; 27 bool q[Maxn]; 28 int sm[Maxn],mx[Maxn],dep[Maxn]; 29 int v[Maxn],vl; 30 31 void dfs(int x,int h,int f) 32 { 33 mx[x]=-1;sm[x]=1; 34 for(int i=first[x];i;i=t[i].next) if(t[i].y!=f&&q[t[i].y]) 35 { 36 int y=t[i].y;//dep[y]=dep[x]+t[i].c; 37 dfs(y,h,x); 38 sm[x]+=sm[y]; 39 mx[x]=mymax(mx[x],sm[y]); 40 } 41 mx[x]=mymax(mx[x],h-sm[x]); 42 if(mx[x]<mx[rt]) rt=x; 43 } 44 45 int get_ans() 46 { 47 int now=1,ans=0; 48 sort(v+1,v+1+vl); 49 for(int i=vl;i>=1;i--) 50 { 51 if(now>i) now=i; 52 while(v[i]+v[now]<=k&&now<i) now++; 53 ans+=now-1; 54 } 55 return ans; 56 } 57 58 void dfs2(int x,int f) 59 { 60 v[++vl]=dep[x]; 61 for(int i=first[x];i;i=t[i].next) if(t[i].y!=f&&q[t[i].y]) 62 { 63 int y=t[i].y; 64 dep[y]=dep[x]+t[i].c; 65 dfs2(y,x); 66 } 67 } 68 69 int fans; 70 71 void ffind(int x,int f) 72 { 73 vl=0;dep[x]=0;dfs2(x,0); 74 fans+=get_ans(); 75 q[x]=0; 76 for(int i=first[x];i;i=t[i].next) if(t[i].y!=f&&q[t[i].y]) 77 { 78 int y=t[i].y; 79 vl=0;dfs2(y,x); 80 fans-=get_ans(); 81 }int i; 82 for(i=first[x];i;i=t[i].next) 83 if(t[i].y!=f&&q[t[i].y]) 84 { 85 rt=0; 86 dfs(t[i].y,x,sm[t[i].y]); 87 ffind(rt,x); 88 } 89 } 90 91 int main() 92 { 93 while(1) 94 { 95 scanf("%d%d",&n,&k); 96 if(n==0&&k==0) break; 97 memset(first,0,sizeof(first)); 98 len=0; 99 for(int i=1;i<n;i++) 100 { 101 int x,y,c; 102 scanf("%d%d%d",&x,&y,&c); 103 ins(x,y,c);ins(y,x,c); 104 } 105 fans=0; 106 memset(q,1,sizeof(q)); 107 mx[0]=INF; 108 rt=0;vl=0;dfs(1,n,0); 109 ffind(rt,0); 110 printf("%d\n",fans); 111 } 112 return 0; 113 }
其实不知道我打的点分治标不标准,感觉很丑。这题就有3个dfs,ffind是求分治的子树答案,dfs是求子树重心,dfs2是求dis以及把子树的dis加入到v中排序。
2016-10-16 22:16:44