2 条题解

  • 0
    @ 2025-11-19 20:23:30

    E63 树形DP P1131 [ZJOI2007] 时态同步

    // 树形DP O(n)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=500010;
    int n,s;
    long long ans,dis[N];
    int head[N],to[N<<1],ne[N<<1],w[N<<1],idx;
    void add(int x,int y,int z){
      to[++idx]=y;w[idx]=z;ne[idx]=head[x];head[x]=idx;
    } 
    
    void dfs(int x,int fa){
      for(int i=head[x];i;i=ne[i]){
        int y=to[i];
        if(y==fa) continue;
        dfs(y,x);
        dis[x]=max(dis[x],dis[y]+w[i]);
      }
      
      for(int i=head[x];i;i=ne[i]){
        int y=to[i];
        if(y==fa) continue;
        ans+=dis[x]-(dis[y]+w[i]);
      }
    }
    int main(){
      scanf("%d%d",&n,&s);
      for(int i=1,x,y,z;i<n;i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
      }
      dfs(s,0);
      printf("%lld",ans);
    }
    
    
    • 0
      @ 2025-11-3 10:30:48
      /*
      n - 1 条边,是一棵树。
      考虑一颗 x 为头的子树,如果想让这棵树的所有结束节点加 n,
      可以直接到 x 头上的边加 n,这样代价最小且合法。
      考虑树形 dp,自底而上递归,不断用最大时间更新。  
      */ 
      #include<bits/stdc++.h>
      using namespace std;
      
      typedef long long LL;
      const int N = 5e5 + 10;
      
      struct node {
      	int x;
      	LL w;
      };
      
      vector<node> G[N];
      int S; LL ans;
      
      LL dfs(int x, int fa, LL sum) {   // 当前节点,父亲节点,到当前节点的代价 
      	LL mx = 0;    // 最大时间 
      	int siz = 0;   // 当前 x 的分支个数 
      	for (node i : G[x]) if (i.x != fa) {
      		int y = i.x; LL w = i.w;
      		
      		LL t = dfs(y, x, sum + w);
      		if (t < mx) {      // 如果 y 的代价比 x 之前分支的代价小 
      			ans += (mx - t);    // 改变 x 到 y 这条边的代价 
      		}
      		else if(mx != 0 && mx < t) {   // 如果之前有分支, y 的代价之前分支的代价小 
      			ans += siz * (t - mx);     // 之前分支的每条边都得改变 
      		}
      		mx = max(mx, t);     // 更新最大值 
      		siz ++;       // 增加分支个数 
      	}
      	
      	if (G[x].size() == 1) {   // 结束节点(只有与父亲节点的一条边) 
      		return sum;
      	}
      	
      	return mx; 
      }
      
      int main () {
      	ios::sync_with_stdio(false);
      	cin.tie(0);
      	
      	int n;
      	cin >> n;
      	cin >> S;
      	for (int i = 1; i < n; i ++) {
      		int x, y; LL w;
      		cin >> x >> y >> w;
      		G[x].push_back({y, w});
      		G[y].push_back({x, w});
      	}
      	
      	ans = 0;
      	dfs(S, 0, 0);
      	cout << ans << "\n";
      	
      	return 0;
      }
      
      
      • 1

      信息

      ID
      2713
      时间
      1000ms
      内存
      256MiB
      难度
      5
      标签
      递交数
      34
      已通过
      15
      上传者