您的位置:首页 > 其它

【BZOJ1468】Tree

2016-01-18 21:45 344 查看

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

Sample Output

5

又是一道点分治的题,方法同聪聪可可。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=40010;
int deep
,head
,son
,f
,d
,root,ans,n,sum,cnt,k;
bool vis
;
struct ee{int to,next,w;}e[N*2];
void insert(int u,int v,int w){
e[++cnt].to=v;e[cnt].next=head[u];e[cnt].w=w;head[u]=cnt;
}

void getroot(int x,int fa){
son[x]=1;f[x]=0;
for (int i=head[x];i;i=e[i].next){
int v=e[i].to;
if (vis[v]||v==fa) continue;
getroot(v,x);
son[x]+=son[v];
f[x]=max(f[x],son[v]);
}
f[x]=max(f[x],sum-f[x]);
if (f[x]<f[root]) root=x;
}

void getdeep(int x,int fa){
deep[++deep[0]]=d[x];
for (int i=head[x];i;i=e[i].next){
int v=e[i].to;
if (vis[v]||v==fa) continue;
d[v]=d[x]+e[i].w;
getdeep(v,x);
}
}

int cal(int x,int now){
int t=0;
d[x]=now;deep[0]=0;
getdeep(x,0);
sort(deep+1,deep+deep[0]+1);
int l=1,r=deep[0];
for (;l<r;) if (deep[l]+deep[r]<=k){t+=r-l;l++;}
else r--;
return t;
}

void work(int x){
ans+=cal(x,0);
vis[x]=1;
for (int i=head[x];i;i=e[i].next){
int v=e[i].to;
if (!vis[v]) {
ans-=cal(v,e[i].w);sum=son[v];root=0;
getroot(v,0);
work(root);
}
}
}

int main(){
scanf("%d",&n);
int u,v,w;
for (int i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
insert(u,v,w);
insert(v,u,w);
}
f[0]=sum=n;
scanf("%d",&k);
getroot(1,0);
work(root);
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: