Computer

Computer

给出一棵有n个节点的无根树,给出(w[x][y])表示x与y的边权,现在询问每个点的到达其他点的最长路径长度(显然不能选它自己),(nleq 10000)

思维预处理

显然为树形递推题目,又要求多个节点的性质,考虑二次递推+换根法,没有根节点,先钦定1为根节点,设(A[x])为以x为根的子树内x的最大路径长度,显然有

[A[x]=max_{yin son(x)}(A[y]+w[x][y]) ]

边界:根节点为0

于是来考虑换根

发现问题

按照老套路,设(B[x])为x的最长路径长度,如图,显然当(B[x])的最优解又y求出,那么求(B[y])时,就不能使用(max(B[x],A[x]))了。

解决问题

理解一:不包括思想(lsy大帝)

既然最优解不能包括y的话,我们设(b[x][y])为求(B[x])的最优解不使用y的值,初始化为求(A[x])时不用y的最优解,如果处理出了这个,那么从x换到y时,(B[y]=max(b[x][y]+l3,A[y]))

现在考虑如何快速求出(b[x][y]),注意到求A时,我们枚举x的子节点时,如果y成为最优解的决策,那么记录下它,枚举一下它的兄弟,这个因为y只有一个,故为(O(n)),然后就可以暴力求出(b[x][y]),对于w,y的兄弟,它不是最优解,所以显然(b[x][w]=A[y]+l3)

于是对于在换根时的处理,我们就要只要把它和从x上面引入来的z的路径长度取个max即可正确求出(c[x][y]),而这个是很好维护的。

理解二:最优解次优解(czf大神)

既然最优解包括了y,我就想办法用最少的空间不包括y,显然次优解可以解决这个问题,设(a[x])为求(A[x])的次优解,同含义(b[x]),对于(a[x])不难得知求出为(O(n)),用它初始化(b[x]),现在考虑维护在从x换到y时的(b[y]),于是发现构成(b[y])的可能性,只有它经过兄弟到y的距离,和从z上面引入的路径,理解1已经告诉我们是(O(n))了,于是可以求出(b[y])

理解三:暴力维护(一个蠢的要死已经失去所有潜力的菜鸡)

发现事实上这样的这样的难处理点很少,一个节点的儿子中有且仅有一个这样满足条件的点,于是考虑暴力维护它,兄弟照套路维护,在从x换到y的时候,y的最优解的组成只有从经过z从上面来的路径,还有经过它的兄弟到达y的路径,和y以下的路径((A[y])已经保存了这个),前两者去个max,记做(czf),设个数组(lsy[x])表示求(B[x])所用的决策节点,特别地,当(lsy[x]=0),代表接下来的换根操作无需考虑,先用(A[x])的最有决策点初始化它,于是当(czf>A[y])时,令(B[y]=czf,pre[y]=0),否则(B[y]=A[y],pre[y])不变。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define ll long long
using namespace std;
struct point{
    int next,to,w;
}ar[20050];
bool check[10015];
ll dp[10015],db[10015];
int at,head[10015],pre[10015];
void dfs1(int),dfs2(int,ll);
il void link(int,int,int);
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        memset(dp,0,sizeof(dp));
        at&=0,memset(head,0,sizeof(head));
        for(int i(2),u,l;i<=n;++i)
            scanf("%d%d",&u,&l),
                link(i,u,l),link(u,i,l);
        dfs1(1),dfs2(1,0);
        for(int i(1);i<=n;++i)
            printf("%lld
",db[i]);
    }
    return 0;
}
void dfs2(int x,ll lsy){
    check[x]&=0;ll czf(0);
    for(ri int i(head[x]);i;i=ar[i].next)
        if(check[ar[i].to]){
            if(pre[x]==i)continue;
            if(db[ar[i].to]<db[x]+ar[i].w)
                db[ar[i].to]=db[x]+ar[i].w,pre[ar[i].to]=0;
            czf=max(czf,dp[ar[i].to]+ar[i].w);
            dfs2(ar[i].to,db[x]+ar[i].w);
        }
    if(pre[x]){
        czf=max(lsy+ar[pre[x]].w,czf+ar[pre[x]].w);
        if(db[ar[pre[x]].to]<czf)
            db[ar[pre[x]].to]=czf,pre[ar[pre[x]].to]=0;
        dfs2(ar[pre[x]].to,czf);
    }
}
void dfs1(int x){
    check[x]|=true;
    for(int i(head[x]);i;i=ar[i].next){
        if(check[ar[i].to])continue;dfs1(ar[i].to);
        if(dp[ar[i].to]+ar[i].w>dp[x])
            dp[x]=dp[ar[i].to]+ar[i].w,pre[x]=i;
    }db[x]=dp[x];
}
il void link(int u,int v,int w){
    ar[++at].to=v,ar[at].w=w;
    ar[at].next=head[u],head[u]=at;
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11007626.html