您的位置:首页 > 编程语言 > C语言/C++

C++之路进阶——点分(tree)

2016-01-19 07:37 381 查看


F.A.QsHomeDiscussProblemSetStatusRanklistContestModifyUser gryz2016Logout捐赠本站
Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入、输出语句及数据类型及范围,避免无谓的RE出现。

1468: Tree

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 774 Solved: 412
[Submit][Status][Discuss]

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

HINT

题解:

点分。。。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn  400100

using namespace std;

int n,m,root,sum,ans,cnt,head[maxn],son[maxn],f[maxn],vis[maxn],deep[maxn],d[maxn];

struct ss
{
int to;
int next;
int w;
}e[maxn];

void insert(int u,int v,int w)
{
e[++cnt].to=v; e[cnt].next=head[u]; e[cnt].w=w; head[u]=cnt;
e[++cnt].to=u; e[cnt].next=head[v]; e[cnt].w=w; head[v]=cnt;
}

void getroot(int x,int fa)
{
son[x]=1;
f[x]=0;
for (int i=head[x];i;i=e[i].next)
if (!vis[e[i].to]&&e[i].to!=fa)
{
getroot(e[i].to,x);
son[x]+=son[e[i].to];
f[x]=max(f[x],son[e[i].to]);
}
f[x]=max(f[x],sum-son[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)
if (!vis[e[i].to]&&e[i].to!=fa)
{
d[e[i].to]=d[x]+e[i].w;
getdeep(e[i].to,x);
}
}

int cal(int x,int now)
{
d[x]=now;
deep[0]=0;
getdeep(x,0);
sort(deep+1,deep+deep[0]+1);
int t=0,l,r;
for(l=1,r=deep[0];l<r;)
{
if(deep[l]+deep[r]<=m){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)
if(!vis[e[i].to])
{
ans-=cal(e[i].to,e[i].w);
sum=son[e[i].to];
root=0;
getroot(e[i].to,root);
work(root);
}
}

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