• 【树形 DP】AcWing 325. 计算机


    我的解法可能比较诡异

    分析

    题意是给你一棵带权的树,求每个点到其它点的最长路。

    因为需要求每个点的,因此考虑换根 dp。

    考虑维护信息:\(f[u]\)\(u\) 到其它点的最长路(也就是所求答案),\(g[u]\)\(u\) 到其它点次长路,\(d_1[u]\) 表示 \(u\) 到其所在子树上的点的最长路,\(d_2[u]\) 表示到其所在子树的点的次长路,\(son[u]\) 表示 \(u\) 所在的最长路所经过的子节点(如果最长路不经过子节点则设为 \(0\))。

    然后我们做两次 dp(约定 \(1\) 号点为根):

    • 第一次将 \(d_1, d_2, son\) 处理出来,同时我们得到了 \(f[1], g[1]\)
    • 第二次更新 \(f, g, son\),利用父节点 \(u\) 更新子节点 \(go\),其中核心部分是分类讨论:如果 \(go\)\(u\)\(son[u]\),那么就需要注意不能再使用 \(f[u]\)\(go\)\(f,g\) 值进行更新。

    更多细节见代码:

    // Problem: 计算机
    // Contest: AcWing
    // URL: https://www.acwing.com/problem/content/327/
    // Memory Limit: 30 MB
    // Time Limit: 1000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include<bits/stdc++.h>
    using namespace std;
    
    #define debug(x) cerr << #x << ": " << (x) << endl
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    
    inline void read(int &x){
        int s=0; x=1;
        char ch=getchar();
        while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
        while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
        x*=s;
    }
    
    const int N=1e4+5, M=N<<1;
    
    struct Edge{
    	int to, next, w;
    }e[M];
    
    int h[N], tot;
    
    void add(int u, int v, int w){
    	e[tot].to=v, e[tot].w=w, e[tot].next=h[u], h[u]=tot++;
    }
    
    int n;
    
    int d1[N], d2[N], son[N];
    
    void dp1(int u, int fa){
    	for(int i=h[u]; ~i; i=e[i].next){
    		int go=e[i].to;
    		if(go==fa) continue;
    		dp1(go, u);
    		
    		int val=e[i].w+d1[go];
    		if(val>=d1[u]) d2[u]=d1[u], d1[u]=val, son[u]=go;
    		else d2[u]=max(d2[u], val);
    	}
    }
    
    int f[N], g[N];
    
    void dp2(int u, int fa){
    	for(int i=h[u]; ~i; i=e[i].next){
    		int go=e[i].to;
    		if(go==fa) continue;
    		
    		if(go==son[u]){
    			if(d1[go]<=e[i].w+g[u]) son[go]=0;
    			f[go]=max(d1[go], e[i].w+g[u]);
    			if(son[go]) g[go]=max(d2[go], e[i].w+g[u]);
    			else g[go]=d1[go];
    		}
    		else{
    			if(d1[go]<=e[i].w+f[u]) son[go]=0;
    			f[go]=max(d1[go], e[i].w+f[u]);
    			if(son[go]) g[go]=max(d2[go], e[i].w+f[u]);
    			else g[go]=d1[go];
    		}
    		
    		dp2(go, u);
    	}
    }
    
    int main(){
    	while(cin>>n){
    		rep(i,1,n) h[i]=-1, d1[i]=d2[i]=f[i]=g[i]=son[i]=0;
    		rep(i,2,n){
    			int u, w; read(u), read(w);
    			add(i, u, w), add(u, i, w);
    		}
    		
    		dp1(1, -1);
    		f[1]=d1[1], g[1]=d2[1];
    		dp2(1, -1);
    		
    		rep(i,1,n) cout<<f[i]<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    ReentrantLock与Condition构造有界缓存队列与数据栈
    ReentrantLock
    文件下载
    scala初学
    bootstrap table 显示连续序号,分页有效
    web中servletcontext和applicationContext
    checkbox是否选中判断
    bookstrap form表单简单-smart-form
    charts柱状图,定时刷新
    js对象和json的区别
  • 原文地址:https://www.cnblogs.com/Tenshi/p/16076252.html
Copyright © 2020-2023  润新知