hdu 5886

求删除树上每一条边之后形成的两个子树中树的直径大者的和

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5+10;
struct edge {
       int from,to,dist;
       edge(int a=0,int b=0,int c=0):from(a),to(b),dist(c){}
};

vector<edge> edges;
vector<int> G[maxn];
ll dp[maxn][4],ans,dp1[maxn][4],res[maxn];
int pos[maxn][4],pos1[maxn][4],n;

void init() {
      edges.clear();
      for (int i = 0; i < maxn; i++) G[i].clear();
      memset(dp,0,sizeof(dp));
      memset(dp1,0,sizeof(dp1));
      memset(res,0,sizeof(res));
      memset(pos,0,sizeof(pos));
      memset(pos1,0,sizeof(pos1));
}

void addedge(int a,int b,int c) {
     edges.push_back((edge){a,b,c});
     edges.push_back((edge){b,a,c});
     int m = edges.size();
     G[a].push_back(m-2);
     G[b].push_back(m-1);
}

void change(int u,int v,ll val) {
     dp[u][3] = val, pos[u][3] = v;
     for (int i = 2; i >= 0; i--) {
        if (dp[u][i] < dp[u][i+1]) {
            swap(dp[u][i],dp[u][i+1]);
            swap(pos[u][i],pos[u][i+1]);
        }
     }
}

void change1(int u,int v,ll val) {
     dp1[u][2] = val, pos1[u][2] = v;
     for (int i = 1; i >= 0; i--) {
        if (dp1[u][i] < dp1[u][i+1]) {
            swap(dp1[u][i],dp1[u][i+1]);
            swap(pos1[u][i],pos1[u][i+1]);
        }
     }
}

ll dfs1(int x,int fa) {
     for (int i = 0; i < G[x].size(); i++) {
        edge e = edges[G[x][i]];
        int v = e.to;
        if (v != fa) {
            ll maxv = dfs1(v,x);
            change(x,v,maxv+e.dist);
            change1(x,v,res[v]);
            res[x] = max(res[x],res[v]);
        }
     }
     res[x] = max(res[x],dp[x][0]+dp[x][1]);
     return dp[x][0];
}

void dfs2(int x,int fa,ll one,ll two) {
   for (int i = 0; i < G[x].size(); i++) {
       edge e = edges[G[x][i]];
       int v = e.to;
       if (v != fa) {
           ll temp = 0, p;
           for (int j = 0; j <= 2; j++) {
               if (pos[x][j] == v) continue;
               else { temp = dp[x][j]; p = pos[x][j]; break; }
           }
           ll newone = max(one,temp);
           ll newtwo = max(two,one+temp);
           ll temp1 = 0;
           for (int j = 0; j <= 2; j++) {
              if (pos[x][j] == v || pos[x][j] == p) continue;
              else { temp1 = dp[x][j]; break; }
           }
           newtwo = max(newtwo,temp+temp1);
           if (pos1[x][0] == v) newtwo = max(newtwo,dp1[x][1]);
           else newtwo = max(newtwo,dp1[x][0]);
           ans += max(newtwo,res[v]);
           dfs2(v,x,newone+e.dist,newtwo);
       }
   }
}

int main()
{
    int t;
    scanf ("%d",&t);
    while(t--) {
        init();
        scanf ("%d",&n);
        int a,b,w;
        for (int i = 1; i <= n-1; i++) {
            scanf ("%d%d%d",&a,&b,&w);
            addedge(a,b,w);
        }
        ans = 0;
        dfs1(1,-1);
        dfs2(1,-1,0,0);
        cout << ans << endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值