题目:https://www.luogu.org/problemnew/show/P4383

关于带权二分:https://www.cnblogs.com/flashhu/p/9480669.html

自己只能想到 “如果把负边看作不存在,那么分出的连通块的直径一定可以被整个连进最终路径里”。然后就不知道连通块不是恰好 K+1 个怎么办,且也不知道是不是对的……

原来可以直接把问题看成 “选出恰好 K+1 条不相交路径” 。这样也考虑到了 “恰好 K 条” 的限制,并且好像挺对的。

结果自己还是不太会……看题解发现原来只需记录 [ 0 / 1 / 2 ] 表示 “未连边” 、 “和孩子连了一条边” 、 “和孩子连了两条边” 就能转移了。

自己把 [ 0 ] 视作 “不向上传” ,那么 return 的时候 [ 0 ] 就可以对 [ 1 ] 、 [ 2 ] 取 max 了。

在 “向上传” 的过程中, [ 2 ] 是没用的。之所以要记录,是为了让 “ [ 1 ] + [ 1 ] ” 的情况不要转移到 [ 0 ] ,这样当前点就不会匹配很多路径了。

于是可以 n*K2 DP。自己写了一下只得了 35 分……

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define ll long long
  5. using namespace std;
  6. int rdn()
  7. {
  8. int ret=;bool fx=;char ch=getchar();
  9. while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
  10. while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
  11. return fx?ret:-ret;
  12. }
  13. ll Mx(ll a,ll b){return a>b?a:b;}
  14. ll Mn(ll a,ll b){return a<b?a:b;}
  15. const int N=3e5+,M=; const ll INF=3e11+;
  16. int n,m,hd[N],xnt,to[N<<],nxt[N<<],w[N<<];
  17. int siz[N]; ll dp[N][][M];
  18. void add(int x,int y,int z)
  19. {to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;}
  20. void cz(int cr,int i,int j,ll s)
  21. {dp[cr][i][j]=Mx(dp[cr][i][j],s);}
  22. void dfs(int cr,int fa)
  23. {
  24. for(int i=;i<;i++)
  25. for(int j=;j<=m;j++) dp[cr][i][j]=-INF;
  26. dp[cr][][]=; siz[cr]=;
  27. for(int i=hd[cr],v;i;i=nxt[i])
  28. if((v=to[i])!=fa)
  29. {
  30. dfs(v,cr); siz[cr]+=siz[v];
  31. for(int j=Mn(siz[cr],m);j>=;j--)
  32. for(int k=;k<=j&&k<=siz[v];k++)
  33. {
  34. cz(cr,,j,dp[cr][][j-k]+dp[v][][k]);
  35. if(k)cz(cr,,j,dp[cr][][j-k+]+dp[v][][k]+w[i]);
  36. cz(cr,,j,Mx(dp[cr][][j-k]+dp[v][][k]+w[i],
  37. dp[cr][][j-k]+dp[v][][k]));
  38. cz(cr,,j,dp[cr][][j-k]+dp[v][][k]);
  39. }
  40. }
  41. for(int j=;j<=m;j++)
  42. dp[cr][][j]=Mx(dp[cr][][j],Mx(dp[cr][][j],dp[cr][][j]));
  43. dp[cr][][]=Mx(dp[cr][][],);
  44. }
  45. int main()
  46. {
  47. n=rdn();m=rdn()+;
  48. for(int i=,u,v,z;i<n;i++)
  49. {
  50. u=rdn();v=rdn();z=rdn();
  51. add(u,v,z);add(v,u,z);
  52. }
  53. dfs(,);
  54. printf("%lld\n",dp[][][m]);
  55. return ;
  56. }

可以用带权二分的知识来优化。

随着 K 的增加,答案是先增大再减小的。可以感性理解。

所以就可以带权二分。二分选一条路径额外带来的收益(可为负),然后不限制路径条数地 DP ,只是附带着记录一下选了几条路。最后看选出来的路径如果多于 K+1 条,说明选一条路径的收益太高;不然说明收益太低。当不看路径条数地 DP 的最优解恰好选了 K+1 条路径时就可以退出了。答案就是现在这个最优解减去 “路径条数 * mid” 。

当路径条数不同但最优解相同地时候,可能二分不到 “恰好 K+1 条路径” 。所以 DP 的时候设第二关键字为路径条数,比如设成值相等时路径越少越好,那么最优解附带的路径条数 <= K+1 的时候也可能就是答案。所以认为答案是二分到的 “最大的 <= K+1 条路径” 的解即可。

关于二分的范围,自己是让 l = 所有正边权之和 , r = 边权最大值。然后 l-- , r++ 。

  想让路径选得最少,考虑选路径的最优情况就是把所有正边权都选上了,所以让 l 为这个值减1,这样最优就是一条边也不选;

  想让路径选得最多,即每个点自己是一条路径。如果不是的话,就是在这个基础上把两个点连在一条路径里,好处是得到一个边权;所以让 r 是最大的边权加1,这样最优就是每个点自己是一条路径。

DP 的转移和暴力一样。

然后调了很久。终于发现自己把 “新增一条路径” 放在 “从孩子转移过来” 之后。这样的话 “以当前点为一个端点的路径” 就不能继承上 “在当前点子树(不含当前点)中完结的路径” 的贡献了!

发现自己的 n*K2 DP 也在这个地方写错了。怪不得是 WA 而不是 TLE ……

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define ll long long
  5. using namespace std;
  6. int rdn()
  7. {
  8. int ret=;bool fx=;char ch=getchar();
  9. while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
  10. while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
  11. return fx?ret:-ret;
  12. }
  13. ll Mn(ll a,ll b){return a<b?a:b;}
  14. ll Mx(ll a,ll b){return a>b?a:b;}
  15. const int N=3e5+;ll INF=3e11+;
  16. int n,m,hd[N],xnt,to[N<<],nxt[N<<],w[N<<];
  17. ll dp[N][],mid; int f[N][];
  18. void add(int x,int y,int z)
  19. {to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;}
  20. void cz(int cr,int i,ll w0,int f0,ll w1,int f1)
  21. {
  22. if(w0==w1) dp[cr][i]=w0,f[cr][i]=Mn(f0,f1);//Mn
  23. else if(w0>w1)dp[cr][i]=w0,f[cr][i]=f0;
  24. else dp[cr][i]=w1,f[cr][i]=f1;
  25. }
  26. void dfs(int cr,int fa)
  27. {
  28. /*dp[cr][0]=0; dp[cr][1]=dp[cr][2]=-INF;
  29. f[cr][0]=0; f[cr][1]=0; f[cr][2]=0;*/
  30. dp[cr][]=; dp[cr][]=mid; dp[cr][]=-INF;
  31. f[cr][]=; f[cr][]=; f[cr][]=;
  32. for(int i=hd[cr],v;i;i=nxt[i])
  33. if((v=to[i])!=fa)
  34. {
  35. dfs(v,cr);
  36. cz(cr,,dp[cr][]+dp[v][]+w[i]-mid,f[cr][]+f[v][]-,
  37. dp[cr][]+dp[v][],f[cr][]+f[v][]);
  38. cz(cr,,dp[cr][]+dp[v][],f[cr][]+f[v][],
  39. dp[cr][]+dp[v][]+w[i],f[cr][]+f[v][]);
  40. dp[cr][]+=dp[v][];
  41. f[cr][]+=f[v][];
  42. }
  43. cz(cr,,dp[cr][],f[cr][],dp[cr][],f[cr][]);
  44. cz(cr,,dp[cr][],f[cr][],dp[cr][],f[cr][]);
  45. //cz(cr,1,dp[cr][1],f[cr][1],mid,1);//new
  46. }
  47. int main()
  48. {
  49. n=rdn();m=rdn()+;ll l=,r=-INF;
  50. for(int i=,u,v,z;i<n;i++)
  51. {
  52. u=rdn();v=rdn();z=rdn();
  53. add(u,v,z); add(v,u,z);
  54. if(z>=)l-=z; r=Mx(r,z);
  55. }
  56. l--; r++; ll ans,ret;
  57. while(l<=r)
  58. {
  59. mid=l+r>>;
  60. dfs(,);
  61. if(f[][]<=m)
  62. {
  63. ans=dp[][];ret=mid;l=mid+;
  64. if(f[][]==m)break;
  65. }
  66. else r=mid-;
  67. }
  68. printf("%lld\n",ans-ret*m);
  69. return ;
  70. }

洛谷 4383 [八省联考2018]林克卡特树lct——树形DP+带权二分的更多相关文章

  1. 洛谷.4383.[八省联考2018]林克卡特树lct(树形DP 带权二分)

    题目链接 \(Description\) 给定一棵边带权的树.求删掉K条边.再连上K条权为0的边后,新树的最大直径. \(n,K\leq3\times10^5\). \(Solution\) 题目可以 ...

  2. dp凸优化/wqs二分学习笔记(洛谷4383 [八省联考2018]林克卡特树lct)

    qwq 安利一个凸优化讲的比较好的博客 https://www.cnblogs.com/Gloid/p/9433783.html 但是他的暴力部分略微有点问题 qwq 我还是详细的讲一下这个题+这个知 ...

  3. 洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)

    题目描述 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做“LCT” 的挑 ...

  4. P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

    $ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的 ...

  5. [八省联考2018]林克卡特树lct——WQS二分

    [八省联考2018]林克卡特树lct 一看这种题就不是lct... 除了直径好拿分,别的都难做. 所以必须转化 突破口在于:连“0”边 对于k=0,我们求直径 k=1,对于(p,q)一定是从p出发,走 ...

  6. LuoguP4383 [八省联考2018]林克卡特树lct

    LuoguP4383 [八省联考2018]林克卡特树lct https://www.luogu.org/problemnew/show/P4383 分析: 题意等价于选择\(K\)条点不相交的链,使得 ...

  7. [八省联考2018]林克卡特树lct

    题解: zhcs的那个题基本上就是抄这个题的,不过背包的分数变成了70分.. 不过得分开来写..因为两个数组不能同时满足 背包的话就是 $f[i][j][0/1]$表示考虑i子树,取j条链,能不能向上 ...

  8. [BZOJ5252][八省联考2018]林克卡特树lct

    bzoj(上面可以下数据) luogu description 在树上选出\(k\)条点不相交的链,求最大权值. 一个点也算是一条退化的链,其权值为\(0\). sol 别问我为什么现在才写这题 首先 ...

  9. P4383 [八省联考2018]林克卡特树lct

    题目链接 题意分析 一句话题意就是 : 让你选出\((k+1)\)条不相交的链 使得这些链的边权总和最大 (这些链可以是点) 我们考虑使用树形\(DP\) \(dp[i][j][0/1/2]\)表示以 ...

随机推荐

  1. 『转』android官网翻译好的蓝牙API接口说明

    Develop API Guides 连接 蓝牙 本文内容 基础知识 蓝牙权限 设置蓝牙 查找设备 查询配对的设备 发现设备 连接设备 连接为服务器 连接为客户端 管理连接 使用配置文件 供应商特定的 ...

  2. 1)jquery validate 远程验证remote,自定义验证 , 手机号验证 2)bootstrap validate 远程remote验证的方法.

    1)jquery  validate 远程验证remote,自定义验证 1-1: js <script src="YYFramework/Public/js/jquery-3.1.1. ...

  3. 关于selenium实现滑块验证

    关于selenium实现滑块验证 python2.7+selenium2实现淘宝滑块自动认证参考链接:https://blog.csdn.net/ldg513783697/article/detail ...

  4. 怪异盒模型和标准盒模型--CSS

    一,原理 css 属性:Box Moel分为两种:W3C标准和IE标准盒子模型. 大多数浏览器采用W3C标准模型,而IE中采用Microsoft自己的标准. 怪异模式是“部分浏览器在支持W3C标准的同 ...

  5. ajax跨域(No 'Access-Control-Allow-Origin' header is present on the requested resource)

    问题 在某域名下使用Ajax向另一个域名下的页面请求数据,会遇到跨域问题.另一个域名必须在response中添加 Access-Control-Allow-Origin 的header,才能让前者成功 ...

  6. python学习笔记第二周

    目录 一.基础概念 1.模块 1)os模块 2)sys模块 2.pyc文件 3.数据类型 1)数字 2)布尔值 3)字符串 4.数据运算 5.运算符 6.赋值运算 7.逻辑运算 8.成员运算 9.身份 ...

  7. Linux make menuconfig查找并快速跳转指定驱动选项

    /********************************************************************** * Linux make menuconfig查找并快速 ...

  8. 配置Glassfish服务器、部署Java web项目、Maven安装配置及JDK版本匹配性问题

    错误一:在win7上通过命令asadmin start-domain启动Glassfish服务器时报错(如下): Exception in thread "main" java.l ...

  9. German Collegiate Programming Contest 2013-B:Booking(贪心)

        Booking Pierre is in great trouble today! He is responsible for managing the bookings for the AC ...

  10. fedora的选择

    Fedora 首页包含3种版本: 工作站,服务器,ATOMIC 个人只要使用工作站即可,然后,下载界面有另一个选择:Silverblue ========================== Silv ...