hdu 5956 The Elder

http://acm.hdu.edu.cn/showproblem.php?pid=5956

 

转移方程:dp[i]=(dis[i]-dis[j])*(dis[i]-dis[j])+P+dp[j]

斜率优化,可持久化单调队列维护

 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001

typedef long long LL;

int P;

int front[N],to[N<<1],nxt[N<<1],val[N<<1],tot;

int dis[N];

int head,tail,q[N];
LL dp[N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
}

inline double X(int i,int j) { return dis[j]-dis[i]; }
inline double Y(int i,int j) { return 1LL*dis[j]*dis[j]+dp[j]-1LL*dis[i]*dis[i]-dp[i]; }

void dfs(int x,int y)
{
    int now_h=head,now_t=tail;
    int l=head,r=tail-2,mid,tmp=-1;
    while(l<=r)
    {
        mid=l+r>>1;
        if(Y(q[mid],q[mid+1])>=2*dis[x]*X(q[mid],q[mid+1])) tmp=mid,r=mid-1;
        else l=mid+1;
    }
    if(tmp!=-1) head=tmp;
    else head=tail-1;
    int j=q[head];
    dp[x]=1LL*(dis[x]-dis[j])*(dis[x]-dis[j])+P+dp[j];
    l=head,r=tail-2,tmp=-1;
    while(l<=r)
    {
        mid=l+r>>1;
        if(Y(q[mid],q[mid+1])*X(q[mid+1],x)<=Y(q[mid+1],x)*X(q[mid],q[mid+1])) tmp=mid,l=mid+1;
        else r=mid-1;
    }
    if(tmp!=-1) tail=tmp+2;
    else tail=head+1;
    int rr=q[tail];
    q[tail++]=x;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y)
        {
            dis[to[i]]=dis[x]+val[i];
            dfs(to[i],x);
        }
    head=now_h; q[tail-1]=rr; tail=now_t;
}


void clear()
{
    tot=0;
    memset(front,0,sizeof(front));
}

int main()
{
    int T;
    read(T);
    int n,u,v,w;
    while(T--)
    {
        clear();
        read(n); read(P);
        for(int i=1;i<n;++i)
        {
            read(u); read(v); read(w);
            add(u,v,w);
        }
        dp[1]=-P;
        for(int i=front[1];i;i=nxt[i])
        {
            head=0; tail=1;
            q[0]=1;
            dis[to[i]]=val[i];
            dfs(to[i],1);
        }
        LL ans=0;
        for(int i=2;i<=n;++i) ans=max(ans,dp[i]);
        cout<<ans<<'\n';
    }
}

 

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8468640.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值