http://acm.hdu.edu.cn/showproblem.php?pid=5242
要活用树链剖分 不能只会更新查询。。
把所有重链找出来排序 贪心的取前k大 因为所有的重链是互不相交的且以叶节点为尾 正好拼成一棵有k个叶子节点的子树 即为所求 但注意这里比较依据不再是子树的节点数量 而是子链权值
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct node
{
int v,next;
};
node edge[2*maxn];
ll val[maxn],maxx[maxn],pre[maxn];
int first[maxn],fa[maxn],deep[maxn],son[maxn],mp1[maxn],mp2[maxn],top[maxn];
int n,k,num,tot;
void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}
void dfsI(int cur)
{
int i,v;
maxx[cur]=0,son[cur]=-1;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa[cur])
{
fa[v]=cur,deep[v]=deep[cur]+1;
dfsI(v);
maxx[cur]=max(maxx[cur],maxx[v]);
if(son[cur]==-1||maxx[son[cur]]<maxx[v]) son[cur]=v;
}
}
maxx[cur]+=val[cur];
}
void dfsII(int cur,int tp)
{
int i,v;
num++;
mp1[cur]=num,mp2[num]=cur,top[cur]=tp;
if(son[cur]==-1) return;
dfsII(son[cur],tp);
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa[cur]&&v!=son[cur]) dfsII(v,v);
}
}
int main()
{
ll ans;
int t,cas,i,u,v;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%lld",&val[i]);
memset(first,-1,sizeof(first));
num=0;
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
fa[1]=0,deep[1]=0;
dfsI(1);
num=0;
dfsII(1,1);
tot=0;
for(i=1;i<=n;i++)
{
if(top[i]==i)
{
pre[++tot]=0,u=i;
while(u!=-1)
{
pre[tot]+=val[u];
u=son[u];
}
}
}
sort(pre+1,pre+tot+1);
ans=0;
for(i=max(1,tot-k+1);i<=tot;i++) ans+=pre[i];
printf("Case #%d: %lld\n",cas,ans);
}
return 0;
}
/*
1
7 1
1 2 3 4 5 6 7
1 2
1 3
2 4
2 5
3 6
3 7
*/