首页 > 其他分享 >P6419 COCI2014-2015#1 Kamp

P6419 COCI2014-2015#1 Kamp

时间:2024-06-06 16:15:21浏览次数:22  
标签:slen int COCI2014 len edge Kamp maxn tot 2015

P6419 COCI2014-2015#1 Kamp

换根 \(dp\) 的 trick。

题面

钦定 \(k\) 个关键点,求每个点出发,访问完所有关键点的距离最小值。

思路

设 \(g_u\) 为从点 \(u\) 出发,访问完子树内所有关键点后,回到点 \(u\) 的距离最小值。

\(s_u\) 为点 \(u\) 子树内关键点个数,\(E(u,v)\) 为边权。

\[g_u=\sum_{v\in u.sons} g_v+ E(u,v)\times 2 \times [s_u>0] \]

自然我们需要换根 dp 求出每个点作为根的时候的 \(g_u\),设这个答案为 \(f_u\)​​。

\(f\) 为 \(u\) 的父亲。

考虑换根转移:

  1. 若 \(s_u=0\),则 \(f_u=g_f+E(f,u)\times 2\),画图显而易见。
  2. 若 \(k-s_u=0\),则 \(f_u=g_u\),都在 \(u\) 的子树内,也显而易见。
  3. 其他情况,则 \(f_u=f_f\),把 \(u\) 作为根,仔细观察一下我们更新的递推式,你会发现 \(f_u=f_f-(g_u-E(u,f))+(g_u+E(u,f))\),化简即可得。

由于车开到最后一个关键点可以不返回 \(u\) 点,而最小访问距离是可以有多重解法的,肯定存在一种方案使得最后访问最距离 \(u\) 最远的点,这样就可以剩下最大距离不用返回 \(u\)​​ 点。

下文所述的最长链,次长连均为关键点作为链的一端的链。

这个貌似可以使用 dfn 序+线段树维护最长链,单次查询复杂度 \(O(\log n)\),但这里也可以利用换根 dp 求最长链。

下面是利用换根 dp 求最长链的思路。

设 \(u\) 子树内到 \(u\) 的最长链长度为 \(len_u\),来自 \(u\) 的儿子 \(id_u\)。

设 \(u\) 子树内到 \(u\) 的次长链长度为 \(slen_u\),要求与 \(len_u\) 来自的儿子不相同。

\(v\) 为 \(u\) 的儿子,有转移:

  1. 若 \(len_u<len_v+E(u,v)\),则 \(slen_u\gets len_u,len_u\gets len_v+E(u,v),id_u\gets v\)。
  2. 若不满足 1 且 \(slen_u<len_v+E(u,v)\),则 \(slen_u\gets len_v+E(u,v)\)​。

变换 \(len_u\) 的意义为到 \(u\) 点的最长链,\(slen_u\) 的意义为和 \(len_u\) 来自不同的 \(u\)​ 所相接的边的次长链。

易得根的 \(len\) 与 \(slen\) 为原来的值。

设 \(f\) 为 \(u\) 的父亲,考虑从根开始的换根转移:

  1. 若 \(len_u<len_f+E(u,f)\) 且 \(id_f\neq u\),则 \(slen_u\gets len_u,len_u\gets len_f+E(u,f),id_u\gets f\)。
  2. 若 \(len_u<slen_f+E(u,f)\),则 \(len_u\gets slen_f+E(u,f),id_u\gets -1\),此时​无论 \(id_u\) 取何值,都不影响下一步转移。
  3. 若 \(slen_u<len_f+E(u,f)\) 且 \(id_f\neq u\),则 \(slen_u\gets len_f+E(u,f)\)​。
  4. 若 \(slen_u<slen_f+E(u,f)\),则 \(slen_u\gets slen_f+E(u,f)\)。

满足上述转移中最靠前的一条,便可以退出转移。

到这里我们变可以输出答案 \(f_i-len_i\)。

CODE

#include<bits/stdc++.h>
using namespace std;

#define ll long long

const int maxn=5e5+5;

struct Edge
{
    int tot;
    int head[maxn];
    struct edgenode{int to,nxt,val;}edge[maxn*2];
    inline void add(int x,int y,int z)
    {
        tot++;
        edge[tot].to=y;
        edge[tot].nxt=head[x];
        edge[tot].val=z;
        head[x]=tot;
    }
}T;

int n,k;
int s[maxn],id[maxn];

ll dp[maxn],f[maxn],len[maxn],slen[maxn];

inline int Max(int a,int b)
{
    if(a<b) return b;
    else return a;
}
inline void dfs_fir(int u,int fa)
{
    for(int i=T.head[u];i;i=T.edge[i].nxt)
    {
        int v=T.edge[i].to;
        if(v==fa) continue;
        dfs_fir(v,u);s[u]+=s[v];
    }
    for(int i=T.head[u];i;i=T.edge[i].nxt)
    {
        int v=T.edge[i].to,w=T.edge[i].val;
        if(v==fa) continue;
        if(!s[v]) continue;
        dp[u]+=dp[v]+w*2;
        if(len[v]+w>=len[u]) slen[u]=len[u],len[u]=len[v]+w,id[u]=v;
        else if(len[v]+w>=slen[u]) slen[u]=len[v]+w;
    }
}
inline void dfs_sec(int u,int fa)
{
    for(int i=T.head[u];i;i=T.edge[i].nxt)
    {
        int v=T.edge[i].to,w=T.edge[i].val;
        if(v==fa) continue;
        if(!s[v]) f[v]=f[u]+w*2,len[v]=len[u]+w;
        else if(k-s[v])
        {
            f[v]=f[u];
            if(id[u]!=v&&len[v]<len[u]+w) slen[v]=len[v],len[v]=len[u]+w,id[v]=u;
            else if(len[v]<slen[u]+w) slen[v]=len[v],len[v]=slen[u]+w,id[v]=-1;
            else if(id[u]!=v&&slen[v]<len[u]+w) slen[v]=len[u]+w;
            else if(slen[v]<slen[u]+w) slen[v]=slen[u]+w;
        }
        else f[v]=dp[v];
        dfs_sec(v,u);
    }
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        T.add(x,y,z),T.add(y,x,z);
    }
    for(int i=1;i<=k;i++)
    {
        int x;
        scanf("%d",&x);
        s[x]=1;
    }
    dfs_fir(1,0);
    f[1]=dp[1];
    dfs_sec(1,1);
    for(int i=1;i<=n;i++) printf("%lld\n",f[i]-len[i]);
}

后记

这个 trick 相较于数据结构优势在于可以 \(O(1)\),劣势在于不可以在线。

标签:slen,int,COCI2014,len,edge,Kamp,maxn,tot,2015
From: https://www.cnblogs.com/binbinbjl/p/18235438

相关文章

  • CSP历年复赛题-P2672 [NOIP2015 普及组] 推销员
    原题链接:https://www.luogu.com.cn/problem/P2672题意解读:N家住户,每家住户与出入口距离是Si米,推销员每走1米疲劳值+1,向第i家住户推销疲劳值+Ai,推销员推销完原路返回出口,计算在向不同数量X的住户推销时,能达到的最大疲劳值。解题思路:本题是一种贪心选择问题,需要思考出可能的最优......
  • 「清新题精讲」P2150 [NOI2015] 寿司晚宴
    P2150[NOI2015]寿司晚宴Statement给定\(n-1\)个数分别为\(2\simn\),从中选出交集为空的两个集合\(A,B\)(集合的并集不必须为\(\{2,\dots,n\}\),且集合可为空)使得不存在\(a\inA,b\inB\)满足\((a,b)\ne1\)(即任意两个数均互质),将方案数对\(p\)取模后输出。\(2\len\le......
  • CSP历年复赛题-P2671 [NOIP2015 普及组] 求和
    原题链接:https://www.luogu.com.cn/problem/P2671题意解读:找到所有符合条件的三元组,累加三元组的分数,结果对10007取模。解题思路:仔细读题,并分析数据规模,1~4个数据点可以通过O(n^2)复杂度解决,也就是枚举法。1、枚举法要求x<y<z,y−x=z−y,移项可得x+z=2*y,并且c......
  • P7860 [COCI2015-2016#2] ARTUR
    原题链接教训1.计算几何,能用乘法就不用除法2.计算几何,开longlong3.计算几何,注意直线的特殊性code#include<bits/stdc++.h>#definelllonglongusingnamespacestd;structnode{llx1,y1,x2,y2;}sk[5005];intcheck(nodea,nodeb){if(a.x2<b.x1||a.x1>b.......
  • [NOIP2015 提高组] 跳石头
    [NOIP2015提高组]跳石头跳石头题目描述一年一度的“跳石头”比赛又要开始了!这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有$N$块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点......
  • [JSOI2015] 染色问题
    [JSOI2015]染色问题题目描述萌萌家有一个棋盘,这个棋盘是一个\(n\timesm\)的矩形,分成\(n\)行\(m\)列共\(n\timesm\)个小方格。现在萌萌和南南有\(C\)种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定:棋盘的每一个小方格既可以染色(染成\(C\)种颜......
  • GB-T 7714-2015
    [1]刘加林、多功能一次性压舌板:中国,92214985.2IP]1993-04-14.[2]河北绿洲生态环境科技有限公司.一种荒漠化地区生态植被综合培育种植方法:中国,01129210.5[P/OL].2001-10-24[2002-05-28].htp:/211.152.9.47/sipoasp/zlijs/hyjs-yxnewasp?recid=0129210.5&leixin.[3]KOSEKIA,M......
  • 【NOIP2015普及组复赛】题3:求和
    题3:求和【题目描述】一条狭长的纸带被均匀划分出了nnn个格子,格子编号从11......
  • 【NOIP2015普及组复赛】题4:推销员
    题4:推销员【题目描述】阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有NNN家......
  • P8624 [蓝桥杯 2015 省 AB] 垒骰子
    原题链接题解code#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconstllmod=1e9+7;lla[7][7]={0},e[7]={0};voidcf1(){lltem[7]={0};for(inti=1;i<=6;i++){for(intj=1;j<=6;j++){t......