HDU - 5956 The Elder (斜率优化dp)

版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/82952425

题目链接

题目大意:有一棵树形的青蛙王国,青蛙长者在根结点,其他的每个结点都有跑得很快的青蛙记者负责向根节点传递新闻,每只青蛙跑长度为L的距离需要花费L^2的时间,途中可以在其他结点把新闻传给另一只青蛙,但需要额外花费P点时间。求从每个结点将新闻传递给根节点所需要花费的最短时间中的最长时间。

解法:根据题意有状态转移方程:dp[i]=min(dp[j]+(sum[i]-sum[j])^{2}+P)(0<=j<i),根据这个方程跑一遍dfs即可,注意回溯的时候撤销操作。

直接转移的复杂度是O(n^2),但这个方程满足斜率单调性,可以用斜率优化降低到O(n)的复杂度。

关于斜率优化,可以参考某位dalao的博客:传送门

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=1e5+100;
int n;
ll a[N],sum[N],d[N],k;
int q[N],hd,tl;
int head[N],to[N<<1],nxt[N<<1],nEdge;
ll cost[N<<1],ans;

void AddEdge(int u,int v,ll c)
{
    nxt[nEdge]=head[u],to[nEdge]=v,cost[nEdge]=c,head[u]=nEdge++;
}

ll dy(int a,int b)
{
    return d[a]+sum[a]*sum[a]-d[b]-sum[b]*sum[b];
}

ll dx(int a,int b)
{
    return 2*(sum[a]-sum[b]);
}

void dfs(int u,int i,int fa)
{
    int oldhd=hd,oldtl=tl;
    while(hd<tl&&dy(q[hd+1],q[hd])<=dx(q[hd+1],q[hd])*sum[i])hd++;
    d[i]=d[q[hd]]+(sum[i]-sum[q[hd]])*(sum[i]-sum[q[hd]])+k;
    ans=max(ans,d[i]);
    while(hd<tl&&dy(i,q[tl])*dx(q[tl],q[tl-1])<=dx(i,q[tl])*dy(q[tl],q[tl-1]))tl--;
    int x=q[++tl];
    q[tl]=i;
    for(int e=head[u];~e;e=nxt[e])
    {
        int v=to[e];
        if(v==fa)continue;
        sum[i+1]=sum[i]+cost[e];
        dfs(v,i+1,u);
    }
    q[tl]=x;
    hd=oldhd,tl=oldtl;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(head,-1,sizeof head);
        nEdge=0;
        scanf("%d%lld",&n,&k);
        for(int i=1; i<n; ++i)
        {
            int u,v;
            ll c;
            scanf("%d%d%lld",&u,&v,&c);
            AddEdge(u,v,c);
            AddEdge(v,u,c);
        }
        hd=0,tl=-1;
        q[++tl]=0;
        d[0]=0;
        ans=0;
        dfs(1,1,0);
        printf("%lld\n",ans-k);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/82952425