zoukankan      html  css  js  c++  java
  • 51nod"省选"模测 A 树的双直径(树形dp)

    题意

    题目链接

    Sol

    比赛结束后才调出来。。不多说啥了,就是因为自己菜。

    裸的up-down dp,维护一下一个点上下的直径就行,一开始还想了个假的思路写了半天。。

    转移都在代码注释里

    毒瘤题目卡空间

    #include<bits/stdc++.h> 
    #define Pair pair<int, int>
    #define MP(x, y) make_pair(x, y)
    #define fi first
    #define se second
    #define LL long long 
    using namespace std;
    const int MAXN = 6e5 + 10;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    template <typename A> inline void debug(A a){cout << a << '
    ';}
    template <typename A> inline LL sqr(A x){return 1ll * x * x;}
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    void print(__int128 x) {
        if (x>9) print(x/10);
        putchar('0'+x%10);
    }
    int N, p[MAXN * 2], ve[MAXN * 2];
    long long f[MAXN], g[MAXN], mxpre[MAXN], mxsuf[MAXN], dl[MAXN], ul[MAXN];
    __int128 ans;
    vector<Pair> v[MAXN];
    void downdfs(int x, int fa) {
    	f[x] = dl[x] = 0;
    	for(auto &tp : v[x]) {
    		int to = tp.fi, w = tp.se;
    		if(to == fa) continue;
    		downdfs(to, x);
    		chmax(dl[x], f[x] + f[to] + w);
    		chmax(f[x], f[to] + w);
    		chmax(dl[x], dl[to]);
    	}
    }
    
    void updfs(int x, int fa) {
    	int cnt = 0;
    	for(int i = 0; i < v[x].size(); i++) 
    		if(v[x][i].fi != fa) p[++cnt] = v[x][i].fi, ve[cnt] = v[x][i].se;
    	
    	mxpre[0] = 0; mxsuf[cnt + 1] = 0;
    	for(int i = 1; i <= cnt; i++) mxpre[i] = max(mxpre[i - 1], f[p[i]] + ve[i]);
    	for(int i = cnt; i >= 1; i--) mxsuf[i] = max(mxsuf[i + 1], f[p[i]] + ve[i]);
    	//一个点向上的直径:
    	//1: 从父亲的ul继承过来
    	//2: 前后缀中的最大值f + 出边 + 入边
    	//3: 父亲的g + 兄弟节点中最大的f + 出边 
    	//4: 前驱/后继 中的最大和次大
    	//5: 前驱/后继 中的子树中的直径 
    
    	for(int i = 1; i <= cnt; i++) {
    		int to = p[i], w = ve[i];
    		chmax(g[to], g[x] + w);
    		chmax(g[to], max(mxpre[i - 1], mxsuf[i + 1]) + w);
    		chmax(ul[to], ul[x]);//1
    		chmax(ul[to], mxpre[i - 1] + mxsuf[i + 1]);//2
    		chmax(ul[to], g[x] + max(mxpre[i - 1], mxsuf[i + 1]));//3
    	}
    	
    	long long mx1 = -1e18, mx2 = -1e18, mx3 = -1e18;
    	for(int i = 1; i <= cnt; i++) {
    		chmax(ul[p[i]], max(mx1 + mx2, mx3)); int tmp = f[p[i]] + ve[i];
    		if(tmp > mx1) chmax(mx2, mx1), mx1 = tmp;
    		else if(tmp > mx2) mx2 = tmp;
    		chmax(mx3, dl[p[i]]);
    	}
    	mx1 = -1e18, mx2 = -1e18, mx3 = -1e18;
    	for(int i = cnt; i >= 1; i--) {
    		chmax(ul[p[i]], max(mx1 + mx2, mx3)); int tmp = f[p[i]] + ve[i];
    		if(tmp > mx1) chmax(mx2, mx1), mx1 = tmp;
    		else if(tmp > mx2) mx2 = tmp;
    		chmax(mx3, dl[p[i]]);
    	}
    	
    	for(int i = 0; i < v[x].size(); i++) 
    		if(v[x][i].fi != fa) updfs(v[x][i].fi, x);
    		
    }
    signed main() {
    	//freopen("a.in", "r", stdin);
        N = read();
        for(int i = 1; i <= N - 1; i++) {
        	int x = read(), y = read(), w = read();
        	v[x].push_back(MP(y, w));
        	v[y].push_back(MP(x, w));
    	}
        downdfs(1, 0);
        updfs(1, 0);
        for(int i = 2; i <= N; i++) chmax(ans, (__int128) dl[i] * ul[i]);
        
        for(int i = 1; i <= N; i++) for(auto &tp : v[i]) tp.se = -tp.se;
        memset(ul, 0, sizeof(ul)); 
        memset(g, 0, sizeof(g));
        downdfs(1, 0);
        updfs(1, 0);
        for(int i = 2; i <= N; i++) chmax(ans, (__int128) dl[i] * ul[i]);
       	print(ans);
       	//cout << ans;
        return 0;
    }
    
  • 相关阅读:
    前端获取当前路径
    pycharm快捷键
    权限(二)
    权限(1)
    cookie,session,用户认证组件
    装饰器
    admin组件的使用
    thinkphp5.0独立配置
    thinkphp5.0读取配置
    thinkphp5.0配置加载
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10548338.html
Copyright © 2011-2022 走看看