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

题意:求一个凸函数的最优解。。。

思路:

好吧在题意里已经说出来了。

对于被卡斜率的,只能\(orz\)了。。。

其实据说还有\(12s\)评测这种操作,对不起我省\(5s\)

好吧不废话了,看看应该怎么做。

暴力的话直接记\(dp[i][j][0->2]\)表示当前做到第 \(i\) 棵子树用了$ j$ 条链并且当前点有\(0->2\)条出边,转移也好想。。。

正解的话。。。就是二分斜率。。

我们记\(f[i][0->2]\)表示做到$ i $子树并且出边是\(0->2\)个。

然后差分,发现单调凸性质,在函数上二分最优解即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 600010;
inline int read()
{
    int q=0,f=1;char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') f=-1;ch=getchar();
    }
    while(isdigit(ch)){
        q=q*10+ch-'0';ch=getchar();
    }
    return q*f;
}

struct node
{
    int x;int y;
    inline void max(int a,int b){
        if(x < a||(x == a && y > b)) x = a,y = b;
    }   
}fp[maxn][3];
node dp[maxn];
node fg[3];
node tmp;
int n,m,k,q;

int cnt;
struct edge
{
    int to;
    int nxt;
    int w;
}e[maxn<<4];
int head[maxn];
inline void add(int u,int v,int w){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;e[cnt].w=w;return;
}
const int inf = 0x7fffffff;
inline void dfs(int x,int f){
    fp[x][0].x=0;fp[x][0].y=0;
    //fp[x][0]=(0,0);
    fp[x][1].x=-q;fp[x][1].y=1;
    fp[x][2].x=-inf;fp[x][2].y=0;
    for(int i = head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y != f){
            dfs(y,x);
            for(int j = 0;j < 3; ++j){
                fg[j]=fp[x][j];
            }
            tmp = dp[y];
            for(int j = 0;j < 3; ++j){
                fp[x][j].max(fg[j].x+tmp.x,fg[j].y+tmp.y);
            }
            fp[x][1].max(fg[0].x+fp[y][1].x+e[i].w,fg[0].y+fp[y][1].y);
            fp[x][2].max(fg[1].x+fp[y][1].x+e[i].w+q,fg[1].y+fp[y][1].y-1);
        }
    }
    dp[x]=fp[x][0];
    for(int i = 1;i < 3; ++i){
        dp[x].max(fp[x][i].x,fp[x][i].y);
    }
    return;
}
int ans;
signed main()
{
    n=read(),m=read();
    ++m;
    for(int i = 1;i < n; ++i){
        int u=read(),v=read(),w=read();
        add(u,v,w);add(v,u,w);
    }
    int l=-inf,r=inf;
    while(l <= r){
        q=(l + r)>>1;
        dfs(1,0);
        if(dp[1].y <= m){
            ans = q;
            r = q - 1;
        }
        else l = q + 1;
    }
    q = ans;
    dfs(1,0);
    cout<<dp[1].x+m*q<<endl;
    return 0;
}

转载于:https://www.cnblogs.com/akoasm/p/9444066.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值