题目描述

  给你一棵树,你要从\(1\)号点出发,经过这棵树的每条边至少一次,最后回到\(1\)号点,经过一条边要花费\(w_i\)的时间。

  你还可以乘车,从一个点取另一个点,需要花费\(c\)的时间。

  你最多做\(k\)次车。

  问最短时间。

  \(k\leq n\leq 20000,w,c\leq 50000\)

题解

  我们考虑把最终路线中坐车的部分替换成走路。

  那么显然不会经过一条边超过两次。

  但是每条边都要经过者少一次,所以每条边只能被一个坐车的路线覆盖。

  所以我们要选择不超过\(k\)条不相交的链,把这些链用\(c\)的代价覆盖掉。

  可以用树上背包做。

  时间复杂度:\(O(nk)\)

  还有有一个网络流的做法:每次找树上最长链,然后用\(c\)的代价覆盖掉,即把路径上的边权取反。

  正解:

  如果我们可以调整乘车的代价,并把乘车次数设为无限次,那么当最优方案的乘车次数不超过\(k\)时最优方案的路线就是最优路线。

  这个东西可以用一次树型DP解决。

  设\(f_i\)为从\(i\)开始遍历以\(i\)为根的子树并回到\(i\)的最小代价和乘车次数,\(g_i\)为从\(i\)开始遍历以\(i\)为根的子树并乘车回到\(i\)的最小代价和乘车次数。

  然后随便DP一下就行了。

  可以观察到,乘车次数是随着乘车代价单调下降的(可能是非连续的),所以可以二分乘车代价,得到答案。

  时间复杂度:\(O(n\log nw)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using namespace std;
typedef unsigned un;
typedef pair<un,un> pii;
const int inf=0x3fffffff;
vector<pii> t[100010];
int n,k,c;
un cost;
pii f[100010];
pii g[100010];
pii operator +(pii a,pii b)
{
return pii(a.first+b.first,a.second+b.second);
}
pii operator -(pii a,pii b)
{
return pii(a.first-b.first,a.second-b.second);
}
void dp(int u,int fa)
{
f[u]=pii(0,0);
g[u]=pii(cost,1);
for(auto a:t[u])
if(a.first!=fa)
{
int v=a.first;
int w=a.second;
dp(v,u);
pii f1=pii(inf,0);
pii g1=pii(inf,0); f1=min(f1,f[u]+f[v]+pii(w,0));
f1=min(f1,f[u]+f[v]+pii(cost,1));
f1=min(f1,f[u]+g[v]);
f1=min(f1,g[u]+f[v]);
f1=min(f1,g[u]+g[v]-pii(cost,1)); g1=min(g1,f[u]+f[v]+pii(cost,1));
g1=min(g1,f[u]+g[v]);
g1=min(g1,g[u]+f[v]+pii(w,0));
g1=min(g1,g[u]+g[v]); f[u]=f1;
g[u]=g1;
}
}
void solve()
{
for(int i=1;i<=n;i++)
t[i].clear();
int x,y,z;
int sum=0;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
t[x].push_back(pii(y,z));
t[y].push_back(pii(x,z));
sum+=z;
}
cost=c;
dp(1,0);
if(f[1].second<=k)
{
printf("%d\n",sum+f[1].first);
return;
}
int l=0,r=inf;
while(l<r)
{
cost=(l+r)>>1;
dp(1,0);
if(f[1].second>k)
l=cost+1;
else
r=cost;
}
cost=l;
dp(1,0);
int ans=f[1].first-k*(l-c)+sum;
printf("%d\n",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
#endif
while(~scanf("%d%d%d",&n,&k,&c))
solve();
return 0;
}

【XSY1905】【XSY2761】新访问计划 二分 树型DP的更多相关文章

  1. BZOJ 1564 :[NOI2009]二叉查找树(树型DP)

    二叉查找树 [题目描述] 已知一棵特殊的二叉查找树.根据定义,该二叉查找树中每个结点的数据值都比它左儿子结点的数据值大,而比它右儿子结点的数据值小. 另一方面,这棵查找树中每个结点都有一个权值,每个结 ...

  2. 【POJ 2486】 Apple Tree(树型dp)

    [POJ 2486] Apple Tree(树型dp) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8981   Acce ...

  3. BZOJ 2286 消耗战 - 虚树 + 树型dp

    传送门 题目大意: 每次给出k个特殊点,回答将这些特殊点与根节点断开至少需要多少代价. 题目分析: 虚树入门 + 树型dp: 刚刚学习完虚树(好文),就来这道入门题签个到. 虚树就是将树中的一些关键点 ...

  4. 初学树型dp

    树型DP DFS的回溯是树形DP的重点以及核心,当回溯结束后,root的子树已经被遍历完并处理完了.这便是树形DP的最重要的特点 自己认为应该注意的点 好多人都说在更新当前节点时,它的儿子结点都给更新 ...

  5. ACM之路(13)—— 树型dp

    最近刷了一套(5题)的树型dp题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=116767#overview,算是入了个门,做下总结. ...

  6. 【题解】Luogu p2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat 树型dp

    题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...

  7. POJ3659 Cell Phone Network(树上最小支配集:树型DP)

    题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. ...

  8. POJ 3342 - Party at Hali-Bula 树型DP+最优解唯一性判断

    好久没写树型dp了...以前都是先找到叶子节点.用队列维护来做的...这次学着vector动态数组+DFS回朔的方法..感觉思路更加的清晰... 关于题目的第一问...能邀请到的最多人数..so ea ...

  9. 洛谷P3354 Riv河流 [IOI2005] 树型dp

    正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...

随机推荐

  1. UVA - 12716 - 异或序列

    求满足GCD(a,b) = a XOR b; 其中1<=b <=a<=n. 首先做这道题需要知道几个定理: 异或:a XOR b = c 那么 a XOR c = b; 那么我们令G ...

  2. (第十三周)Final Review会议

    项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 Final Review会议 时间:2016.12.2   13:00——15:00 地点:冬华楼一楼大厅 会 ...

  3. message:GDI+ 中发生一般性错误。

    图片类型的文件保存的时候出了问题,可能是路径出错,也可能是保存到的文件夹不存在导致(发布项目的时候如果文件夹是空的,文件夹将不存在)

  4. E: 无法打开锁文件 /var/lib/dpkg/lock-frontend - open (13: 权限不够)E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-frontend),请查看您是否正以 root 用户运行?

    一.解决方案 修改root密码,以root身份安装 sudo pwdroot root  # 输入新密码即可

  5. 简单封装mongodb

    首先安装mongodb  npm i mongodb --save 简单封装,在modules目录下新建db.js var MongoClient=require('mongodb').MongoCl ...

  6. winform使用相关

    1.回车键触发按钮点击事件——回车登录 设置窗体的AccessButton属性 2.密码框样式设置 设置PasswordChar为想要的密码显示的样式,如*  3.设置窗口居中 设置StartPosi ...

  7. nodejs配置nginx 以后链接mongodb数据库

    服务器 :windows server2008 R2 反向代理 :nginx 1.15.1 for window 64位 数据库:mongodb 4 64位 使用框架express 首先下载nodej ...

  8. 容错处理try

    var num = 90; try{ console.log( num + 100 ); consolel.log(aaa); }catch(e){ console.log("如果程序中有异 ...

  9. C\C++学习笔记 2

    C++记录4 自动存储: 生命周期在代码块,存储在栈,后入先出. 静态存储: 存在于程序的整个周期. 动态存储: 使用new delete 在内存池(堆)存储,不受程序生命周期控制. 内存泄露: 没有 ...

  10. POJ1108_Split Windows 解题报告

    Split Windows 题目链接:http://poj.org/problem?id=1108 题目大意: 给你一棵二叉树的先序遍历,有三种字符:|.-.A~Z,然后用窗口表示出来,|: 表示将当 ...