Computer

Computer

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

思维预处理

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

\[A[x]=\max_{y\in 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\n",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;
}

posted @ 2019-06-12 09:14  a1b3c7d9  阅读(354)  评论(0编辑  收藏  举报