Game HDU - 5242

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
*/

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/83181769