[二分][dp凸优化] Luogu P4383 林克卡特树lct

题目描述

小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战。

游戏中有一个叫做“LCT” 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益;若vi < 0 ,则表示走这条边需要支付- vi 的过路费。小L 需要控制主角Link 切掉(Cut)树上的 恰好K 条边,然后再连接 K 条边权为 0 的边,得到一棵新的树。接着,他会选择树上的两个点p; q ,并沿着树上连接这两点的简单路径从p 走到q ,并为经过的每条边支付过路费/ 获取相应收益。

海拉鲁大陆之神TemporaryDO 想考验一下Link。他告诉Link,如果Link 能切掉 合适的边、选择合适的路径从而使 总收益 - 总过路费最大化的话,就把传说中的大师之剑送给他。

小 L 想得到大师之剑,于是他找到了你来帮忙,请你告诉他,Link 能得到的 总收益 - 总过路费最大是多少。

 

题解

  • 大爷的题解比较详细就直接上大爷的题解吧  戳戳戳

 

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring> 
 4 #define ll long long
 5 const int inf=1e13,N=300010;
 6 struct edge { int v,w,from; }e[N<<1];
 7 int n,k,cnt,head[N];
 8 ll sum,q,l,r,ans;
 9 void insert(int u,int v,int w) { e[++cnt].v=v,e[cnt].w=w,e[cnt].from=head[u],head[u]=cnt; }
10 struct data
11 {
12     int c; ll v;
13     data operator + (data d) {data a;a.v=v+d.v;a.c=c+d.c;return a;}
14     bool operator < (data d) {return v<d.v||(v==d.v&&c<d.c);}
15 }f[N][3],p[3];
16 data be(ll v, int c) {data d;d.v=v;d.c=c;return d;}
17 data max(data a,data b) {return a<b?b:a;}
18 void dfs(int u,int fa)
19 {
20     for (int i=head[u];i;i=e[i].from)
21     {
22         int v=e[i].v;
23         if (v==fa) continue;
24         dfs(v,u),f[u][2]=max(f[u][2]+f[v][0],f[u][1]+f[v][1]+be(e[i].w-q,1)),f[u][1]=max(f[u][0]+f[v][1]+be(e[i].w,0),f[u][1]+f[v][0]),f[u][0]=f[u][0]+f[v][0];
25     }
26     f[u][0]=max(f[u][0],max(f[u][1]+be(-q,1),f[u][2]));
27 }   
28 void check(ll x)
29 {
30     q=x;
31     for (int i=1;i<=n;i++) f[i][0]=be(0,0),f[i][2]=be(-q,1),f[i][1]=be(0,0);
32     dfs(1,0),sum=f[1][0].v,cnt=f[1][0].c;
33 }
34 int main()
35 {
36     scanf("%d%d",&n,&k),k++;
37     for (int i=1,u,v,w;i<n;i++) scanf("%d%d%d",&u,&v,&w),insert(u,v,w),insert(v,u,w),r+=(w>0)?w:-w;
38     l=-r;
39     while (l<=r) 
40     {
41         ll mid=(l+r)>>1;
42         check(mid);
43         if (cnt>=k) l=mid+1,ans=mid; else r=mid-1;
44     }
45     check(ans),printf("%lld",sum+k*ans);
46 }

 

题目描述

小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战。

游戏中有一个叫做“LCT” 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益;若vi < 0 ,则表示走这条边需要支付- vi 的过路费。小L 需要控制主角Link 切掉(Cut)树上的 恰好K 条边,然后再连接 K 条边权为 0 的边,得到一棵新的树。接着,他会选择树上的两个点p; q ,并沿着树上连接这两点的简单路径从p 走到q ,并为经过的每条边支付过路费/ 获取相应收益。

海拉鲁大陆之神TemporaryDO 想考验一下Link。他告诉Link,如果Link 能切掉 合适的边、选择合适的路径从而使 总收益 - 总过路费最大化的话,就把传说中的大师之剑送给他。

小 L 想得到大师之剑,于是他找到了你来帮忙,请你告诉他,Link 能得到的 总收益 - 总过路费最大是多少。

posted @ 2019-07-26 11:39  BEYang_Z  阅读(217)  评论(0编辑  收藏  举报