• Luogu P3647 [APIO2014]连珠线


    题目
    换根dp。
    显然对于给定的一棵有根树,蓝线都不能拐弯。
    (f_{u,0})表示(u)不是蓝线中点时子树内的答案,(f_{u,1})表示(u)是蓝线中点时子树内的答案。(以(1)为根的情况下)
    那么显然有(f_{u,0}=sumlimits_{vin son_u}max(f_{v,0},f_{v,1}+d_v))
    (son_u)表示(u)的儿子集合,(d_u)表示((u,fa_u))的长度)
    但是(f_{u,1})如何求?
    我们这样考虑:穿过(u)的蓝线就一条,我们枚举这条蓝线到它的哪个儿子,这个儿子的单独算,其它的儿子的答案则和上面一样(这一部分可以直接蒯下来而不必另算)。
    (f_{u,1}=f_{u,0}+maxlimits_{vin son_u}(f_{v,0}+d_v-max(f_{v,0},f_{v,1}+d_v)))
    然后我们可以(O(n^2))做了对吧。
    再设(g_{u,0,v})表示和上面一样的意义,并且不考虑(u)的孩子(v)情况下的答案。
    显然有(g_{u,0,v}=f_{u,0}-max(f_{v,0},f_{v,1}+d_v))
    (g_{u,1,t}=g_{u,0,t}+maxlimits_{vin son_uwedge v eq t}(f_{v,0}+d_v-max(f_{v,0},f_{v,1}+d_v)))
    这个我们可以在每次计算(f_{u,1})时处理出((f_{v,0}+d_v-max(f_{v,0},f_{v,1}+d_v)))的最大值和次大值来计算。
    然后开始换根。
    还是dfs,对于(u)以及(vin son_u),我们这样计算:
    (g_{u,?,v})赋给(f_{u,?}),然后把父亲的(f)以及(d_u)合并到(u)来,再统计答案。
    这样我们可以保证在((1,u))这条链上,每个点都只计算了这条链以外儿子的子树的答案以及连接它自己和它的父亲的答案,即(u)(v)以外子树的答案。
    具体的看看代码能够很轻松地理解。

    #include<bits/stdc++.h>
    #define pi pair<int,int>
    #define pb push_back
    using namespace std;
    const int N=200003,inf=1e9;
    vector<pi>E[N];int f[N][2],fa[N],d[N],ans;vector<int>son[N],g[N][2],mx[N];
    int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
    int max(int a,int b){return a>b? a:b;}
    int min(int a,int b){return a<b? a:b;}
    void dfs(int u)
    {
        int mx1=-inf,mx2=-inf,x;
        for(auto [v,w]:E[u])
        {
    	if(v==fa[u]) continue;
    	d[v]=w,fa[v]=u,son[u].pb(v),dfs(v),f[u][0]+=max(f[v][0],f[v][1]+w),x=f[v][0]+w-max(f[v][0],f[v][1]+w); 
    	if(x>mx1) mx2=mx1,mx1=x; else if(x>mx2) mx2=x;
        }
        f[u][1]=f[u][0]+mx1;
        for(auto [v,w]:E[u])
        {
    	if(v==fa[u]) continue;
    	g[u][0].pb(f[u][0]-max(f[v][0],f[v][1]+w)),x=f[v][0]+w-max(f[v][0],f[v][1]+w);
    	x==mx1? (g[u][1].pb(g[u][0].back()+mx2),mx[u].pb(mx2)):(g[u][1].pb(g[u][0].back()+mx1),mx[u].pb(mx1));
        }
    }
    void dp(int u)
    {
        for(int i=0;i<son[u].size();++i)
        {
            f[u][0]=g[u][0][i],f[u][1]=g[u][1][i];
            if(fa[u]) f[u][0]+=max(f[fa[u]][0],f[fa[u]][1]+d[u]),f[u][1]=f[u][0]+max(mx[u][i],f[fa[u]][0]+d[u]-max(f[fa[u]][0],f[fa[u]][1]+d[u]));
            ans=max(ans,f[son[u][i]][0]+max(f[u][0],f[u][1]+d[son[u][i]])),dp(son[u][i]);
        }
    }
    int main()
    {
        int i,n,u,v,w;n=read();
        for(i=1;i<n;++i) u=read(),v=read(),w=read(),E[u].pb(pi(v,w)),E[v].pb(pi(u,w));
        dfs(1),dp(1),cout<<ans;
    }
    
  • 相关阅读:
    仿网易/QQ空间视频列表滚动连播炫酷效果
    UIScrollerView当前显示3张图
    iOS AVPlayer视频播放器
    iOS 购物车动画
    C++从零实现简单深度神经网络(基于OpenCV)
    Android 轻松实现仿淘宝地区选择
    微信小程序之下拉刷新,上拉更多列表实现
    iOS 指南针
    tableView 获取网络图片,并且设置为圆角(优化,fps)
    黑客技术 —— Linux 命令行
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11743616.html
Copyright © 2020-2023  润新知