奶酪

题目描述

CJY很喜欢吃奶酪,于是YJC弄到了一些奶酪,现在YJC决定和CJY分享奶酪。
YJC弄到了n-1块奶酪,于是他把奶酪挂在了一棵n个结点的树上,每根树枝上挂一块奶酪,每块奶酪都有重量。
YJC和CJY决定这样分奶酪:首先砍掉一根树枝,把树分成两部分,每人取一部分,然后各自在自己取的那部分树上选择一条路径并取走路径上的奶酪,然后把剩下的奶酪拿去喂老鼠。
两人都想让自己取走总重量尽量大的奶酪,但他们不知道砍掉哪一根树枝最好。所以他们想让你计算,对于每一根树枝,砍掉之后每个人取走的奶酪的总重量的最大值。

做法

树形DP
和挺进一样的做法

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=4000000+10;
const ll mo=2333333333333333;
ll f1[maxn][2],f2[maxn][2],f3[maxn][2],num[maxn][2],who[maxn][2],sum[maxn],f[maxn],g[maxn],gg[maxn];
int h[maxn],go[maxn*2],dis[maxn*2],next[maxn*2],id[maxn],fa[maxn],v[maxn];
int dl[maxn];
bool bz[maxn],pd[maxn];
int i,j,k,l,t,n,m,tot,head,tail,now;
ll p,q,ans;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void add(int x,int y,int z){
    go[++tot]=y;
    dis[tot]=z;
    next[tot]=h[x];
    h[x]=tot;
}
void dfs(){
    dl[tail=1]=1;
    head=0;
    int x,y,t;
    while (head<tail){
    x=dl[++head];y=fa[x];
    t=h[x];
    while (t){
        if (go[t]!=y){
            id[go[t]]=(t+1)/2;
            v[go[t]]=dis[t];
            fa[go[t]]=x;
            dl[++tail]=go[t];
        }
        t=next[t];
    }
    }
    int i;
    fd(i,tail,2){
        t=0;
        go[t]=dl[i];dis[t]=v[go[t]];
        x=fa[go[t]];
        ll l=f1[go[t]][0]+(ll)dis[t];
            if (l>f1[x][0]){
                f3[x][0]=f2[x][0];
                f3[x][1]=f2[x][1];
                f2[x][0]=f1[x][0];
                f2[x][1]=f1[x][1];
                f1[x][0]=l;
                f1[x][1]=go[t];
            }
            else if (l>f2[x][0]){
                f3[x][0]=f2[x][0];
                f3[x][1]=f2[x][1];
                f2[x][0]=l;
                f2[x][1]=go[t];
            }
            else if (l>f3[x][0]){
                f3[x][0]=l;
                f3[x][1]=go[t];
            }
            l=max(num[go[t]][0],f1[go[t]][0]+f2[go[t]][0]);
            if (l>num[x][0]){
                num[x][1]=num[x][0];
                who[x][1]=who[x][0];
                num[x][0]=l;
                who[x][0]=go[t];
            }
            else if (l>num[x][1]){
                num[x][1]=l;
                who[x][1]=go[t];
            }
    }
}
void dg(){
    int x,y,i,t;
    fo(i,1,tail){
        x=dl[i];y=fa[x];
        if (y){
        if (who[y][0]==x) sum[x]=num[y][1];else sum[x]=num[y][0];
        if (f1[y][1]==x) sum[x]=max(sum[x],f2[y][0]+f3[y][0]);
        else if (f2[y][1]==x) sum[x]=max(sum[x],f1[y][0]+f3[y][0]);
        else sum[x]=max(sum[x],f1[y][0]+f2[y][0]);
        if (f1[y][1]==x) f[x]=f2[y][0];else f[x]=f1[y][0];
        g[x]=(ll)v[y]+g[y];
        g[x]=max(g[x],(ll)v[y]+f[y]);
        gg[x]=gg[y];
        gg[x]=max(gg[x],f[x]+g[x]);
        gg[x]=max(gg[x],sum[x]);
    }
    }
}
int main(){
    freopen("cheese.in","r",stdin);freopen("cheese.out","w",stdout);
    n=read();
    fo(i,1,n-1){
        j=read();k=read();l=read();
        add(j,k,l);add(k,j,l);
    }
    dfs();
    dg();
    fo(i,2,n){
        k=id[i];
        p=max(num[i][0],f1[i][0]+f2[i][0]);q=gg[i];
        if (p>q) swap(p,q);
        (ans+=q*23333%mo);
        if (ans>=mo) ans-=mo;
        (ans+=p*2333%mo);
        if (ans>=mo) ans-=mo;
        (ans+=(ll)233*k*k%mo);
        if (ans>=mo) ans-=mo;
        (ans+=(ll)23*k%mo);
        (ans+=2);
        if (ans>=mo) ans-=mo;
        if (ans>=mo) ans-=mo;
    }
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值