传送门:

很常规的一道树规,转为左儿子右兄弟。

然后$f[node][anc][K]$表示在node节点上,最近的有贡献祖先在anc上,在node的儿子和兄弟上有k个有贡献节点的最优值。

然后得出以下转移方程。

$f[node][anc][K]=min\{f[son[node]][anc][k]+f[bro[node]][anc][K-k]\}+Value[node]*(dis[node]-dis[anc])$无贡献

$f[node][anc][K]=min\{f[son[node]][node][k]+f[bro[node]][anc][K-1-k]\}$                                              有贡献

下面是代码实现:

 //BZOJ 1812
 //by Cydiater
 //2016.9.5
 #include <iostream>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <string>
 #include <algorithm>
 #include <queue>
 #include <map>
 #include <ctime>
 #include <cmath>
 #include <iomanip>
 using namespace std;
 #define ll long long
 #define up(i,j,n)        for(int i=j;i<=n;i++)
 #define down(i,j,n)        for(int i=j;i>=n;i--)
 ;
 const int oo=0x3f3f3f3f;
 inline int read(){
     ,f=;
     ;ch=getchar();}
     +ch-';ch=getchar();}
     return x*f;
 }
 ,fa[MAXN],f[MAXN][MAXN][MAXN],pre_fa[MAXN];
 struct edge{
     int y,next,v;
 }e[MAXN<<];
 namespace solution{
     inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
     void dfs(int node){
         for(int i=LINK[node];i;i=e[i].next){
             dis[e[i].y]=dis[node]+e[i].v;
             dfs(e[i].y);
         }
     }
     void init(){
         N=read();K=read();
         pre_fa[]=-;
         up(i,,N){
             Value[i]=read();int y=read(),v=read();
             pre_fa[i]=y;
             insert(y,i,v);
         }
         dfs();dis[]=;
     }
     void build(int node,int father){
         int tmp=LINK[node];son[node]=e[tmp].y;fa[node]=father;
         if(tmp)build(e[tmp].y,node);node=e[tmp].y;
         for(int i=e[tmp].next;i;i=e[i].next){
             bro[node]=e[i].y;build(e[i].y,node);
             node=e[i].y;
         }
     }
     void TreeDP(int node){
         if(son[node])TreeDP(son[node]);
         if(bro[node])TreeDP(bro[node]);
         int father=pre_fa[node];
         ){
             up(lim,,K)up(k,,lim){
                 int tmp=Value[node]*(dis[node]-dis[father]);
                 if(son[node])tmp+=f[son[node]][father][k];
                 if(bro[node])tmp+=f[bro[node]][father][lim-k];
                 f[node][father][lim]=min(f[node][father][lim],tmp);
             }
             up(lim,,K)up(k,,lim){
                 ;
                 ];
                 if(bro[node])tmp+=f[bro[node]][father][lim-k];
                 f[node][father][lim]=min(f[node][father][lim],tmp);
             }
             father=pre_fa[father];
         }
         ){
             father=;
             up(lim,,K)up(k,,lim){
                 ;
                 if(son[node])tmp+=f[son[node]][father][k];
                 if(bro[node])tmp+=f[bro[node]][father][lim-k];
                 f[node][father][lim]=min(f[node][father][lim],tmp);
             }
         }
     }
     void slove(){
         build(,-);
         memset(f,0x3f,sizeof(f));
         TreeDP();
         printf(][][K]);
     }
 }
 int main(){
     //freopen("input.in","r",stdin);
     using namespace solution;
     init();
     slove();
     ;
 }

BZOJ1812 [IOI2005]river的更多相关文章

  1. [Ioi2005]River

    设f[i][j][k]表示i上游最近的一个伐木场为j且在i所在的子树里共建了k个伐木场(不包含在i的)的最小运费和 设v为u的儿子,dist[u]为u到0号点的距离. 则当i>=j时 f[u][ ...

  2. bzoj1812 [Ioi2005]riv

    riv 几乎整个Byteland王国都被森林和河流所覆盖.小点的河汇聚到一起,形成了稍大点的河.就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海.这条大河的入海口处有一个村庄--名叫B ...

  3. [IOI2005]River 河流

    题目大意: 给定n个点的有根树,每条边有边权,每个点有点权w, 你要在k个点上建立伐木场,对于每个没有建伐木场的点x,令与它最近的祖先.有伐木场的点,为y,你需要支付dis(x,y)*w[x]的代价. ...

  4. BZOJ1812: [Ioi2005]riv(树形dp)

    题意 题目链接 Sol 首先一个很显然的思路是直接用\(f[i][j] / g[i][j]\)表示\(i\)的子树中选了\(j\)个节点,该节点是否选的最小权值.但是直接这样然后按照树形背包的套路转移 ...

  5. bzoj1812 [IOI2005]riv河流

    题目链接 problem 给出一棵树,每个点有点权,每条边有边权.0号点为根,每个点的代价是这个点的点权\(\times\)该点到根路径上的边权和. 现在可以选择最多K个点.使得每个点的代价变为:这个 ...

  6. [学习笔记]对未来做出承诺的DP小结

    这是一种DP状态设计方法. 有些题,当你必须以一个顺序往后填的话,然而后面的填法会对之前产生影响,那么,不妨在之前就对未来怎么填做出承诺. 通俗的讲,就是对未来打一个表. 然后后面填的时候,直接查表转 ...

  7. 【BZOJ1812】[Ioi2005]riv 树形DP

    [BZOJ1812][Ioi2005]riv Description 几乎整个Byteland王国都被森林和河流所覆盖.小点的河汇聚到一起,形成了稍大点的河.就这样,所有的河水都汇聚并流进了一条大河, ...

  8. 【BZOJ1812】riv(多叉树转二叉树,树形DP)

    题意:给定一棵树,每个点有权值,每条边有边权(单向边).你可以选取K个黑点,使得从每个点移动到距离他最近的黑点的花费(距离*点权)的总和最小. n<=100 k<=50 w[i],a[i] ...

  9. Moon River

    读书笔记系列链接地址http://www.cnblogs.com/shoufengwei/p/5714661.html.        昨晚无意中听到了一首英文歌曲,虽不知其意,但是瞬间就被优美的旋律 ...

随机推荐

  1. RabbitHub开源情况及计划

    之前写过一篇".NET 平台下的插件化开发内核(Rabbit Kernel)",已经过去三个月了,期间RabbitHub并不是没有了发展更不是放弃了发展,在RabbitHub中的群 ...

  2. 移动OA,致我们终将逝去的青春(程序员版)[转]

    移动OA和致青春有什么关系,难道说赵薇也来做手机应用了?为什么不行,当年小燕子代言的打印机可是红火的很,现在再秀一把时尚手机办公也未必不可啊.言归正转,本文还是以点代面阐述移动OA开发过程,但是,它的 ...

  3. js如何判断一个数组

    typeof [] 为一个"object" 不能通过此方法判断一个数组 方法 1.instanceof方法,这个方法用的比较多. 2.这个是es5以后推荐的方法,Object.pr ...

  4. 离散系统频响特性函数freqz()

    MATLAB提供了专门用于求离散系统频响特性的函数freqz(),调用freqz()的格式有以下两种: l        [H,w]=freqz(B,A,N) B和A分别为离散系统的系统函数分子.分母 ...

  5. JavaScript学习笔记-简单的计时钟表

    <!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...

  6. scrollTop和offsetTop的区别,scrollTopLeft和offsetLeft的区别

    scrollTop和offsetTop的区别:scrollTop是指某个可滚动区块向下滚动的距离,比如向下滚动了10个像素,那么这个元素的scrollTop属性值就是10,这个属性的值是可读写的,且不 ...

  7. js中递归函数的使用介绍

    所谓的递归函数就是在函数体内调用本函数.使用递归函数一定要注意,处理不当就会进入死循环.递归函数只有在特定的情况下使用 ,比如阶乘问题 递归函数是在一个函数通过名字调用自身的情况下构成的,如下所示: ...

  8. Java 构建器

    假如我们的一个实体类有很多的属性值,但是这些属性值又是可选的.如果我们遇到这样的是类,如何设计出方便的实体类呢? 通常解决办法一: 重叠构造器 public class User { private ...

  9. jsp内置对象作业3-application用户注册

    1,注册页面 zhuCe.jsp <%@ page language="java" contentType="text/html; charset=UTF-8&qu ...

  10. 【转】HTTP协议详解

    原文地址:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436.html 一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则 ...