HDU - 59562016ACM/ICPC亚洲区沈阳站I - The Elder 树上斜率优化dp

Posted walfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 59562016ACM/ICPC亚洲区沈阳站I - The Elder 树上斜率优化dp相关的知识,希望对你有一定的参考价值。

题意:给定上一棵树,然后每条边有一个权值,然后每个点到 1 的距离有两种,第一种是直接回到1,花费是 dist(1, i)^2,还有另一种是先到另一个点 j,然后两从 j 向1走,当然 j 也可以再向 k,一直到1,但经过一个点,那么就会出多一个花费 p,问你每个点到 1 的最小距离的最大值是多少。

题解:dp【i】代表从1节点出发,向下传递到i节点的最小花费,dp[i]=min(dp[j]+dis[i]-dis[j])^2,j是从i到1链上的每一个点,很明显的斜率优化,dis[i]是i到根节点的距离

dp[i]+2*dis[i]dis[j]= dis[j]+dis[i]*dis[i]+dis[j]*dis[j];

b  +   k      *  x  =   y

需要注意的 是在dfs的时候要记录一下上一层的head和last和q[last+1],因为改变的只有最后覆盖的last+1,方便退回到原来的状态

技术分享图片
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)

using namespace std;

const double g=10.0,eps=1e-12;
const int N=100000+10,maxn=1000000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;

vector<pair<int,ll> >v[N];
ll dis[N],dp[N],ans,P;
int q[N],head,last;
struct node{
    int head,last;
    int id,change;
}p[N];
inline ll x(int j)
{
    return dis[j];
}
inline ll y(int j)
{
    return dp[j]+dis[j]*dis[j];
}
inline double slope(int i,int j)
{
//    printf("------%d %d\n", i, j);
    return (y(i)-y(j))/(x(i)-x(j));
}
void dfsdis(int u,int f,ll val)
{
    dis[u]=val;
    for(int i=0;i<v[u].size();i++)
    {
        int x=v[u][i].fi;
        if(x!=f)dfsdis(x,u,val+v[u][i].se);
    }
//    printf("%d %d\n",u,dis[u]);
}
void dfs(int u,int f)
{
    for(int i=0;i<v[u].size();i++)
    {
        int x=v[u][i].fi;
        if(x!=f)
        {
//            for(int j=head;j<=last;j++)printf("%d ",q[j]);printf("%d\n",x);
            p[x].head=head,p[x].last=last;
            while(head<last&&slope(q[head],q[head+1])<2*dis[x])head++;
            int te=q[head];
            dp[x]=dp[te]+(dis[x]-dis[te])*(dis[x]-dis[te])+P;
//            printf("%lld %d %lld\n",P,x,dp[x]);
            ans=max(ans,dp[x]);
            while(head<last&&slope(q[last-1],q[last])>slope(q[last],x))last--;
            p[x].id=last+1,p[x].change=q[last+1];
            q[++last]=x;
            dfs(x,u);
            head=p[x].head,last=p[x].last;
            q[p[x].id]=p[x].change;
//            for(int j=head;j<=last;j++)printf("%d ",q[j]);printf("%d\n",x);
        }
    }
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d%d",&n,&P);
        for(int i=1;i<=n;i++)v[i].clear();
        for(int i=1;i<n;i++)
        {
            int u,vv;ll w;
            scanf("%d%d%lld",&u,&vv,&w);
            v[u].pb(mp(vv,w));
            v[vv].pb(mp(u,w));
        }
        dfsdis(1,-1,0);
        head=1,last=1;q[head]=1;dp[1]=-P;
        ans=0;
        dfs(1,-1);
        printf("%lld\n",ans);
    }
    return 0;
}
/***********************
3
6 10
1 2 4
2 3 5
1 4 3
4 5 3
5 6 3
***********************/
View Code

 

以上是关于HDU - 59562016ACM/ICPC亚洲区沈阳站I - The Elder 树上斜率优化dp的主要内容,如果未能解决你的问题,请参考以下文章

hdu55272015ACM/ICPC亚洲区长春站 Too Rich

(HDU 5558) 2015ACM/ICPC亚洲区合肥站---Alice's Classified Message(后缀数组)

2014ACM/ICPC亚洲区北京站题解

hdu-4810 Wall Painting 2013ACM/ICPC亚洲区南京站现场赛

HDU 5950 Recursive sequence 递推+矩阵快速幂 (2016ACM/ICPC亚洲区沈阳站)

HDU 5112 A Curious Matt (2014ACM/ICPC亚洲区北京站-重现赛)