zoukankan      html  css  js  c++  java
  • bzoj3743【题解】Kamp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743

    这道题第一想法是暴力。

    但是没有细分数据点。

    硬想了半天没有思路。

    只好去搜题解。但是题解看着好麻烦的。

    于是就综合了很多题解的思路。

    选择用两次树形DP

    第一次先求一些必要的值。

    把第一个关键点设为根。从它开始DP。

    第二次也是一样,以第一个为根,更新答案。

    细节可以看注释。

    如下。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=500005;
    int n,k,tot,head[maxn],d[maxn];
    bool have[maxn<<1];
    struct node{
        int nxt,dis,to;
        #define nxt(x) e[x].nxt
        #define dis(x) e[x].dis
        #define to(x) e[x].to
    }e[maxn<<1];
    inline void add(int from,int to,int v){
        to(++tot)=to;dis(tot)=v;
        nxt(tot)=head[from];head[from]=tot;
    }
    int num[maxn];//以它为根的子树中有多少关键点。
    ll f[2][maxn],val[maxn];//f[0][x]表示从x向下走到下一个关键点的最大长,f[1][x]是次大
    inline void doo1(int now,int fa){
        num[now]=have[now];
        for(int i=head[now];i;i=nxt(i)){
            int t=to(i);
            if(t==fa) continue;
            doo1(t,now);
            if(!num[t]) continue;
            num[now]+=num[t];
            val[now]+=val[t]+dis(i);
            int tmp=f[0][t]+dis(i);
            if(tmp>f[0][now]){ 
                f[1][now]=f[0][now];
                f[0][now]=tmp;
            }else if(tmp>f[1][now])
                    f[1][now]=tmp;
        }
    }
    ll ans[maxn];//答案
    inline void push(int now,int fa){
        for(int i=head[now];i;i=nxt(i)){
            int t=to(i);
            if(t==fa) continue;
            ans[t]=ans[now]+dis(i);
            push(t,now);
        }
    }
    //up表示now到上一个关键点的距离
    inline void doo2(int now,int fa,ll up,ll sum){
        ans[now]=2*sum-max(up,f[0][now]);//更新答案,画图可以得到
        for(int i=head[now];i;i=nxt(i)){
            int t=to(i);
            if(t==fa) continue;
            if(num[t]){//如果to是关键点求up
                ll tmp=0;
                if(up||have[now]) tmp=max(tmp,up+dis(i));
                if(f[0][now]==f[0][t]+dis(i)){
                    if(f[1][now])
                        tmp=max(tmp,f[1][now]+dis(i));
                }else
                    tmp=max(tmp,f[0][now]+dis(i));
                doo2(t,now,tmp,sum);
            }else{//直接求然后下放
                ans[t]=ans[now]+dis(i);
                push(t,now);
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n-1;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);add(y,x,z);
        }
        for(int i=1;i<=k;i++)
            scanf("%d",&d[i]),have[d[i]]=1;
        doo1(d[1],0);
        doo2(d[1],0,0,val[d[1]]);
        for(int i=1;i<=n;i++)
            printf("%lld
    ",ans[i]);
        system("pause");
        return 0;
    }
  • 相关阅读:
    205. Isomorphic Strings
    8 旋转数组的最小数字
    303. Range Sum Query
    70. Climbing Stairs
    HDU 5971 Wrestling Match (二分图)
    URAL 2019 Pair: normal and paranormal (STL栈)
    URAL 2021 Scarily interesting! (贪心+题意)
    URAL 2018 The Debut Album (DP)
    HDU 5236 Article (概率DP+贪心)
    HDU 5241 Friends (大数)
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11262826.html
Copyright © 2011-2022 走看看