zoukankan      html  css  js  c++  java
  • [二分][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 能得到的 总收益 - 总过路费最大是多少。

  • 相关阅读:
    cookie行为试验(一)
    指针内容的引用
    多线程协同
    xss攻击
    _com_error e
    操作符重载
    c++对象中的成员变量地址分布
    常对象指针
    COM调用2
    cookie行为试验(二)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11249290.html
Copyright © 2011-2022 走看看