Codeforces Round #722 (Div. 2) - C. Parsa‘s Humongous Tree - 树形DP

Posted Chivas_/Regal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #722 (Div. 2) - C. Parsa‘s Humongous Tree - 树形DP相关的知识,希望对你有一定的参考价值。

一道不错的树形dp入门题
题目:
在这里插入图片描述
思路:
这种题可以大胆猜选端点值

第一想法是贪心
有两种答案
第奇数步的结点上res1选左端点,res2选右端点
偶数步反过来

但是贪了半天发现果然不行
于是去现场学了一发树形dp。。

dp出最优解的端点值
要么当前结点选左端点,从子结点的左右端点构造出的dp选一个
要么当前节点选右端点,从子节点的左右端点构造出的dp选一个
于是要开两个dp,代表以左端点结尾或者右端点结尾构造方式,输出最大的那个就行了

得转移方程:
dp[father][0] += MAX(abs(l[father] - l[son]) + dp[son][0], abs(l[father] - r[son]) + dp[son][1])
dp[father][1] += MAX(abs(r[father] - l[son]) + dp[son][0], abs(r[father] - r[son]) + dp[son][1])

cout << MAX(dp[1][0], dp[1][1]) << endl

/*
           ________   _                                              ________                              _
          /  ______| | |                                            |   __   |                            | |
         /  /        | |                                            |  |__|  |                            | |
         |  |        | |___    _   _   _   ___  _   _____           |     ___|   ______   _____   ___  _  | |
         |  |        |  __ \\  |_| | | | | |  _\\| | | ____|          |  |\\  \\    |  __  | |  _  | |  _\\| | | |
         |  |        | |  \\ |  _  | | | | | | \\  | | \\___           |  | \\  \\   | |_/ _| | |_| | | | \\  | | |
         \\  \\______  | |  | | | | \\ |_| / | |_/  |  ___/ |          |  |  \\  \\  |    /_   \\__  | | |_/  | | |
Author :  \\________| |_|  |_| |_|  \\___/  |___/|_| |_____| _________|__|   \\__\\ |______|     | | |___/|_| |_|
                                                                                         ____| |
                                                                                         \\_____/
*/
#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <utility>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define G 10.0
#define LNF 1e18
#define EPS 1e-6
#define PI acos(-1.0)
#define INF 0x7FFFFFFF

#define ll long long
#define ull unsigned long long

#define LOWBIT(x) ((x) & (-x))
#define LOWBD(a, x) lower_bound(a.begin(), a.end(), x) - a.begin()
#define UPPBD(a, x) upper_bound(a.begin(), a.end(), x) - a.begin()
#define TEST(a) cout << "--------- " << a << " ---------" << '\\n'

#define CHIVAS int main()
#define _REGAL exit(0)

#define SP system("pause")
#define IOS ios::sync_with_stdio(false)
#define map unordered_map

#define _int(a) int a; cin >> a
#define  _ll(a) ll a; cin >> a
#define _char(a) char a; cin >> a
#define _string(a) string a; cin >> a
#define _vectorInt(a, n) vector<int>a(n); cin >> a
#define _vectorLL(a, b) vector<ll>a(n); cin >> a

#define PB(x) push_back(x)
#define ALL(a) a.begin(),a.end()
#define MEM(a, b) memset(a, b, sizeof(a))
#define EACH_CASE(cass) for (cin >> cass; cass; cass--)

#define LS l, mid, rt << 1
#define RS mid + 1, r, rt << 1 | 1
#define GETMID (l + r) >> 1

using namespace std;

template<typename T> inline void Read(T &x){T f = 1; x = 0;char s = getchar();while(s < '0' || s > '9'){if(s == '-') f = -1; s = getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;}
template<typename T> inline T MAX(T a, T b){return a > b? a : b;}
template<typename T> inline T MIN(T a, T b){return a > b? b : a;}
template<typename T> inline void SWAP(T &a, T &b){T tp = a; a = b; b = tp;}
template<typename T> inline T GCD(T a, T b){return b > 0? GCD(b, a % b) : a;}
template<typename T> inline void ADD_TO_VEC_int(T &n, vector<T> &vec){vec.clear(); cin >> n; for(int i = 0; i < n; i ++){T x; cin >> x, vec.PB(x);}}
template<typename T> inline pair<T, T> MaxInVector_ll(vector<T> vec){T MaxVal = -LNF, MaxId = 0;for(int i = 0; i < (int)vec.size(); i ++) if(MaxVal < vec[i]) MaxVal = vec[i], MaxId = i; return {MaxVal, MaxId};}
template<typename T> inline pair<T, T> MinInVector_ll(vector<T> vec){T MinVal = LNF, MinId = 0;for(int i = 0; i < (int)vec.size(); i ++) if(MinVal > vec[i]) MinVal = vec[i], MinId = i; return {MinVal, MinId};}
template<typename T> inline pair<T, T> MaxInVector_int(vector<T> vec){T MaxVal = -INF, MaxId = 0;for(int i = 0; i < (int)vec.size(); i ++) if(MaxVal < vec[i]) MaxVal = vec[i], MaxId = i; return {MaxVal, MaxId};}
template<typename T> inline pair<T, T> MinInVector_int(vector<T> vec){T MinVal = INF, MinId = 0;for(int i = 0; i < (int)vec.size(); i ++) if(MinVal > vec[i]) MinVal = vec[i], MinId = i; return {MinVal, MinId};}
template<typename T> inline pair<map<T, T>, vector<T> > DIV(T n){T nn = n;map<T, T> cnt;vector<T> div;for(ll i = 2; i * i <= nn; i ++){while(n % i == 0){if(!cnt[i]) div.push_back(i);cnt[i] ++;n /= i;}}if(n != 1){if(!cnt[n]) div.push_back(n);cnt[n] ++;n /= n;}return {cnt, div};}
template<typename T>             vector<T>& operator--            (vector<T> &v){for (auto& i : v) --i;            return  v;}
template<typename T>             vector<T>& operator++            (vector<T> &v){for (auto& i : v) ++i;            return  v;}
template<typename T>             istream& operator>>(istream& is,  vector<T> &v){for (auto& i : v) is >> i;        return is;}
template<typename T>             ostream& operator<<(ostream& os,  vector<T>  v){for (auto& i : v) os << i << ' '; return os;}

const int maxn = 1e5 + 10;
ll n;
ll head[maxn << 2];
struct edge{
        ll nxt, to;
}edge[maxn << 2];
ll cnt = 0;
ll l[maxn], r[maxn];
ll res;
ll dp[maxn << 2][2];//后面那一维是两种不同的构造模式所建立的答案
ll x[maxn], y[maxn];

inline void Init(){
        for(ll i = 0; i < n * 2 + 10; i ++) head[i] = -1, dp[i][0] = dp[i][1] = 0;
        cnt = 0;
}

inline void add_edge(ll from, ll to){
        edge[++cnt] = {head[from], to};
        head[from] = cnt;
}

inline void DFS(ll x, ll cur){//树遍历
        for(int i = head[x]; ~i; i = edge[i].nxt){
                int u = edge[i].to;
                if(u == cur) continue;
                DFS(u, x);
                //后序遍历:回溯出结果
                dp[x][0] += MAX(abs(l[x] - l[u]) + dp[u][0], abs(l[x] - r[u]) + dp[u][1]);//当前元素选左端点
                dp[x][1] += MAX(abs(r[x] - l[u]) + dp[u][0], abs(r[x] - r[u]) + dp[u][1]);//当前元素选右端点
        }
}

inline void solve(){
        cin >> n; Init();
        for(ll i = 1; i <= n; i ++) cin >> l[i] >> r[i];
        for(ll i = 0; i < n - 1; i ++){
                cin >> x[i] >> y[i];
                add_edge(x[i], y[i]);
                add_edge(y[i], x[i]);
        }
        DFS(1, -1);
        cout << MAX(dp[1][0], dp[1][1]) << endl;//从两种答案中选一种
}

CHIVAS{IOS;
        int cass;
        EACH_CASE(cass){
                solve();
        }
        _REGAL;
}

以上是关于Codeforces Round #722 (Div. 2) - C. Parsa‘s Humongous Tree - 树形DP的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #722 (Div. 2) 20210525

Codeforces Round #722 (Div. 2)Codeforces-1529 ABC

Codeforces Round #722 (Div. 2)Codeforces-1529 ABCD

Codeforces Round #722 (Div. 2)Codeforces-1529 ABCD

Codeforces Round #722 (Div. 2) 部分题解

Codeforces Round #722 (Div. 2) A~D 题解