肥宅快乐树 换根+树形DP/dfs

肥宅快乐树是一棵神秘而巨大的树,它长有许多枝条和节点,每条枝连接树中两个节点,每个节点上都长有一瓶肥宅快乐水。 何老板是肥宅快乐水的资深爱好者。历经艰难,他终于找到了这棵传说中的快乐树。他想要获取树上所有的快乐水,迫不及待地想从树根往树上爬。 每经过一条树枝都会耗费一定体力。而且快乐树自带防御功能,即每条枝上都有一个一次性陷阱,一旦踏上该枝,何老板就会被立即弹射回地面,他得重新从根往上爬。 (注1:一次性陷阱是指,陷阱只在第一次经过该枝时有效) (注2:从i号点回到i的父亲节点,不耗费体力) 每个节点上都有开有一些肥宅快乐花,花的香气可以让何老板经过当前节点所连的树枝时,耗费的体力值减少。不同节点的快乐花数量不一,产生的减少体力消耗的效果也不一定相同。 何老板发现快乐树还有一个神秘“换根”功能。何老板可以将指定节点变换为树根,变换后,树中树枝连接情况保持不变。但是只能进行一次换根操作。 快乐树共n个节点,编号1到n,开始时1号点为根。 何老板想知道,以哪个节点为根才能使他收集齐n瓶快乐水耗费的总体力最少。请你帮你计算。


发现每条边都经过儿子节点的size值
换根的话只有一条边的贡献改变
考虑换根的话 可以dfs 也可以树形DP 以子树为状态
code:

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define maxnn 1000010
#define ll long long
int n;
ll las[maxnn],en[maxnn],le[maxnn],tot,nex[maxnn];
ll size[maxnn],w[maxnn];
int mark[maxnn];
ll ans=0;
ll root=1;
ll cnt=0;
ll aass=0;
ll pos=0; 

void add(int a,int b,ll c)
{
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
    le[tot]=c;
}
void dfs1(int v,int fa)
{
    size[v]=1;
    for(int i=las[v];i;i=nex[i])
    {
            int u=en[i];
            if(u!=fa)
            {
                dfs1(u,v);
                size[v]+=size[u];
            } 

    } 

}
void dfs2(int v,int fa)
{
    for(int i=las[v];i;i=nex[i])
    {
            int u=en[i];
            if(u!=fa)
            {
                ans=ans+le[i]*size[u]-size[u]*w[v];
                dfs2(u,v);
            }
    }
}
void huan(int v,int fa)
{
    for(int i=las[v];i;i=nex[i])
    {
        int u=en[i];
        if(u!=fa&&(!mark[u]))
        {
            int tmp1=size[v]-size[u];
            int tmp2=size[v];
            int tmp3=size[u];
            mark[u]=1;
            ans=ans-le[i]*size[u]+size[u]*w[v]+(size[v]-size[u])*(le[i]-w[u]);
            size[u]=size[u]+tmp1;
            size[v]=tmp1;
            if(aass>ans)
            {
                pos=u;
                aass=ans;
            }
            huan(u,v);
            ans=ans+le[i]*tmp3-tmp3*w[v]-(tmp2-tmp3)*(le[i]-w[u]);
            size[v]=tmp2;
            size[u]=tmp3;
        }
    }
}
int main()
{
    //freopen("happytree.in","r",stdin);
    //freopen("happytree.out","w",stdout);
    ll x,y,z;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&w[i]);
    }
    for(int i=1;i<n;i++)
    {
        scanf("%lld%lld%lld",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    dfs1(1,1);
    pos=1;
    dfs2(1,1);
    aass=ans;mark[1]=1;
    huan(root,root);
    cout<<pos<<endl;
    cout<<aass<<endl;
}

原文地址:https://www.cnblogs.com/OIEREDSION/p/11565434.html

时间: 2024-08-11 03:30:35

肥宅快乐树 换根+树形DP/dfs的相关文章

2014 Super Training #9 E Destroy --树的直径+树形DP

原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其他点的最远距离最小).现在你要破坏所有叶子节点到根节点的连通,每条边破坏都需要一定能量.你有一个能量为power的武器,能破坏能量小于等于power的任何路.求最少需要的power. 解法参考博客:http://blog.csdn.net/gzh1992n/article/details/86511

肥宅快乐数

肥宅快乐数 Time limit:1s Memory limit:128M Description 作为一个肥宅,栗酱每天都从不同的事物上获得快乐.今天他发现每一个形如 (i,j) 的二元组当满足 "i + j == i | j" 时都会给他带来1点快乐.现在问题来了,[1, 2^k] 以内的正整数一共能带给栗酱多少点快乐呢? 答案对1e+7取模 Input 数据的第一行是数据组数T. 在每组数据中:第一行是一个整数k. T <= 128 k <= 128 Output 每

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.Find out the

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

[模拟赛10.12] 老大 (二分/树的直径/树形dp)

[模拟赛10.12] 老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n ? 1 条边的无向连通图),由于新建的办公室太大以至于要将奖杯要分放在两个不同的地方以便同学们丢硬币进去开光,OB 想请你帮帮他看看奖杯放在哪两个办公室使得在任意一个在劳模办公室做题的小朋友能最快地找到奖杯来开光. 一句话题意:给出一个 n 个点的树,在两个合适且不同的点放上奖杯,使得每个点到最近的奖杯距离最大值最小. 输入

POJ 1655 Balancing Act[树的重心/树形dp]

Balancing Act 时限:1000ms Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

POJ 1655 BalanceAct 3107 Godfather (树的重心)(树形DP)

参考网址:http://blog.csdn.net/acdreamers/article/details/16905653 树的重心的定义: 树的重心也叫树的质心.找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡. 通常利用树形DP找重心: BalanceAct: http://poj.org/problem?id=1655 题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最

HDU1011树形DP+DFS

/* 自己的第一道树形DP题 HDU1011题意: 深搜+树形DP 为了阐述的简便,先解释输入数据 输入n和m,n为定点数,m为人数 之后n行为cost[i],score[i]分别为第i点需要耗费的体力和可以得到的分数 之后n-1行为构造树,规定了1点为树根 读到-1 -1结束 下面解释cost,score 每个人有20点体力值,在每个点可以分配人数,当人数*20>=cost[i]时,可以得到第i点的score[i] 但是每个人最多分配在一个点上 求最多得到的分数 思路:构数之后DP 为叶子结点