标签:
http://acm.hdu.edu.cn/showproblem.php?pid=5242
2 5 2 4 3 2 1 1 1 2 1 5 2 3 2 4 5 3 4 3 2 1 1 1 2 1 5 2 3 2 4
Case #1: 10 Case #2: 11
/**
hdu 5242 树链剖分找权值最大的前k条链
题目大意:给定一个树形的游戏网络,可以从根节点出发k个人,每个人可以沿着一条路径走下去,不能回头,出口在各个叶子节点,在路过一个节点时可以
获得该点的权值,每个点的权值只能被获得一次,问k个人怎样走最后可以获得的权值最多
解题思路:首先从反向建立一棵有向树(从叶子节点到根节点),首先dfs1找出每个节点到根节点的最大权路径,然后按权值递减排序,dfs2找每个点到根节点
的最大权路径,走过的点不能重复走,最后在这些最大权路径中取前k大即为答案
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=100005;
typedef long long LL;
int n,m;
LL a[maxn],x[maxn];
int head[maxn],ip;
bool vis[maxn];
void init()
{
memset(head,-1,sizeof(head));
ip=0;
}
struct note
{
int v,next;
}edge[maxn*2];
struct node
{
LL sum;
int id;
bool operator <(const node &other)const
{
return sum>other.sum;
}
}p[maxn];
void addedge(int u,int v)
{
edge[ip].v=v,edge[ip].next=head[u],head[u]=ip++;
}
LL dfs1(int u)
{
if(vis[u])return p[u].sum;
vis[u]=1;
p[u].sum=a[u];
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
p[u].sum+=dfs1(v);
}
return p[u].sum;
}
LL dfs2(int u)
{
if(vis[u])return 0;
vis[u]=1;
LL x=a[u];
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
x+=dfs2(v);
}
return x;
}
int main()
{
int T,tt=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
p[i].id=i;
}
init();
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(y,x);
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(!vis[i])
dfs1(i);
}
sort(p+1,p+n+1);
/*for(int i=1;i<=n;i++)
{
printf("%d:%d\n",p[i].id,p[i].sum);
}*/
memset(x,0,sizeof(x));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
x[i]=dfs2(p[i].id);
}
sort(x+1,x+n+1);
LL ans=0;
for(int i=n;i>=1&&i>n-m;i--)
{
ans+=x[i];
}
printf("Case #%d: %I64d\n",++tt,ans);
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/lvshubao1314/article/details/46299887