BZOJ1468:Tree(点分治)
Description
给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K
Input
N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k
Output
一行,有多少对点之间的距离小于等于k
Sample Input
7
1 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10
1 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10
Sample Output
5
Solution
点分治模板
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #define N (40000+10) 6 using namespace std; 7 struct node 8 { 9 int to,next,len; 10 }edge[N*2]; 11 int n,k,sum,root,ans; 12 int head[N],num_edge; 13 int depth[N],d[N],size[N],maxn[N]; 14 bool vis[N]; 15 void add(int u,int v,int l) 16 { 17 edge[++num_edge].to=v; 18 edge[num_edge].len=l; 19 edge[num_edge].next=head[u]; 20 head[u]=num_edge; 21 } 22 23 void Get_root(int x,int fa) 24 { 25 size[x]=1; maxn[x]=0; 26 for (int i=head[x];i!=0;i=edge[i].next) 27 if (edge[i].to!=fa && !vis[edge[i].to]) 28 { 29 Get_root(edge[i].to,x); 30 size[x]+=size[edge[i].to]; 31 maxn[x]=max(maxn[x],size[edge[i].to]); 32 } 33 maxn[x]=max(maxn[x],sum-size[x]); 34 if (maxn[x]<maxn[root]) root=x; 35 } 36 37 void Get_depth(int x,int fa) 38 { 39 depth[++depth[0]]=d[x]; 40 for (int i=head[x];i!=0;i=edge[i].next) 41 if (edge[i].to!=fa && !vis[edge[i].to]) 42 { 43 d[edge[i].to]=d[x]+edge[i].len; 44 Get_depth(edge[i].to,x); 45 } 46 } 47 48 int Calc(int x,int cost) 49 { 50 d[x]=cost; depth[0]=0; 51 Get_depth(x,0); 52 sort(depth+1,depth+depth[0]+1); 53 int l=1,r=depth[0],cnt=0; 54 while (l<r) 55 if (depth[l]+depth[r]<=k) 56 cnt+=r-l,l++; 57 else 58 r--; 59 return cnt; 60 } 61 62 void Solve(int x) 63 { 64 ans+=Calc(x,0); 65 vis[x]=true; 66 for (int i=head[x];i!=0;i=edge[i].next) 67 if (!vis[edge[i].to]) 68 { 69 ans-=Calc(edge[i].to,edge[i].len); 70 sum=size[edge[i].to]; 71 root=0; 72 Get_root(edge[i].to,0); 73 Solve(root); 74 } 75 } 76 77 int main() 78 { 79 int u,v,l; 80 scanf("%d",&n); 81 sum=maxn[0]=n; 82 for (int i=1;i<=n-1;++i) 83 { 84 scanf("%d%d%d",&u,&v,&l); 85 add(u,v,l); add(v,u,l); 86 } 87 scanf("%d",&k); 88 Get_root(1,0); 89 Solve(root); 90 printf("%d",ans); 91 }