【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
又是一道点分治的题,方法同聪聪可可。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=40010; 5 int deep[N],head[N],son[N],f[N],d[N],root,ans,n,sum,cnt,k; 6 bool vis[N]; 7 struct ee{int to,next,w;}e[N*2]; 8 void insert(int u,int v,int w){ 9 e[++cnt].to=v;e[cnt].next=head[u];e[cnt].w=w;head[u]=cnt; 10 } 11 12 void getroot(int x,int fa){ 13 son[x]=1;f[x]=0; 14 for (int i=head[x];i;i=e[i].next){ 15 int v=e[i].to; 16 if (vis[v]||v==fa) continue; 17 getroot(v,x); 18 son[x]+=son[v]; 19 f[x]=max(f[x],son[v]); 20 } 21 f[x]=max(f[x],sum-f[x]); 22 if (f[x]<f[root]) root=x; 23 } 24 25 void getdeep(int x,int fa){ 26 deep[++deep[0]]=d[x]; 27 for (int i=head[x];i;i=e[i].next){ 28 int v=e[i].to; 29 if (vis[v]||v==fa) continue; 30 d[v]=d[x]+e[i].w; 31 getdeep(v,x); 32 } 33 } 34 35 int cal(int x,int now){ 36 int t=0; 37 d[x]=now;deep[0]=0; 38 getdeep(x,0); 39 sort(deep+1,deep+deep[0]+1); 40 int l=1,r=deep[0]; 41 for (;l<r;) if (deep[l]+deep[r]<=k){t+=r-l;l++;} 42 else r--; 43 return t; 44 } 45 46 void work(int x){ 47 ans+=cal(x,0); 48 vis[x]=1; 49 for (int i=head[x];i;i=e[i].next){ 50 int v=e[i].to; 51 if (!vis[v]) { 52 ans-=cal(v,e[i].w);sum=son[v];root=0; 53 getroot(v,0); 54 work(root); 55 } 56 } 57 } 58 59 int main(){ 60 scanf("%d",&n); 61 int u,v,w; 62 for (int i=1;i<n;i++){ 63 scanf("%d%d%d",&u,&v,&w); 64 insert(u,v,w); 65 insert(v,u,w); 66 } 67 f[0]=sum=n; 68 scanf("%d",&k); 69 getroot(1,0); 70 work(root); 71 printf("%d",ans); 72 }