换根树形DP
#include #include #include #include #include #include #include #include #include #include <string> #include #include #include #include #include #include #include <set> #include #include // #include // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<#define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef unsigned long long ull; typedef long double ld; typedef pair<int, int> pii; typedef pair pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; template inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 1e5+9; int a[maxn],b[maxn]; vector<int>mp[maxn]; int n; ll dpa[maxn][2], dpb[maxn][2]; ///dpa[u][0]表示a从u开始选最大所能得,需要从dpb最小的转移过来,实际是个最小值 ///dpa[u][1] 表示次小值。 ///dpb[u][0]表示b的,它只能从dpa最大的转移过来,实际上是个最大值。 ///dpb[u][1]表示次大值 int sona[maxn], sonb[maxn]; void dfs1(int u, int fa) { dpa[u][0] = dpa[u][1] = inff; dpb[u][0] = dpb[u][1] = -inff; sona[u] = sonb[u] = 0; for(int v : mp[u]) { if(v == fa) continue; dfs1(v, u); if(dpb[v][0] + a[u] - b[u] <= dpa[u][1]) { dpa[u][1] = dpb[v][0] + a[u] - b[u]; if(dpa[u][1] < dpa[u][0]) { swap(dpa[u][1] , dpa[u][0]); sona[u] = v; } } if(dpa[v][0] + a[u] - b[u] >= dpb[u][1]) { dpb[u][1] = dpa[v][0] + a[u] - b[u]; if(dpb[u][1] > dpb[u][0]) { swap(dpb[u][1], dpb[u][0]); sonb[u] = v; } } } ///度数为1的节点需要特殊判断,还要区分根节点和叶子节点 if(mp[u].size() <= 1 && fa != 0) { dpa[u][0] = dpb[u][0] = a[u] - b[u]; } } ll ans; ll cupa[maxn], cupb[maxn]; void dfs2(int u, int fa) { ll tmp = min(dpa[u][0], cupa[u]); if(mp[u].size() == 1 && fa) tmp = cupa[u]; ans = max(ans, tmp); for(int v : mp[u]) { if(v == fa) continue; cupa[v] = max(cupb[u], dpb[u][ sonb[u] == v ? 1: 0]) + a[v] - b[v]; cupb[v] = min(cupa[u], dpa[u][ sona[u] == v ? 1: 0]) + a[v] - b[v]; dfs2(v, u); } } int main(){ int T; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); for(int i=1; i<=n; i++) scanf("%d", &b[i]); for(int i=1; i) { int u,v; scanf("%d%d", &u, &v); mp[u].pb(v); mp[v].pb(u); } dfs1(1, 0); ans = dpa[1][0]; if(mp[1].size() == 1) cupa[1] = cupb[1] = a[1] - b[1]; else cupa[1] = inff, cupb[1] = -inff; dfs2(1, 0); printf("%lld\n", ans); for(int i=1; i<=n; i++) mp[i].clear(); } return 0; }
用到了color coding技巧。
参考和学习
/* * @Author: chenkexing * @Date: 2019-08-16 22:30:07 * @Last Modified by: chenkexing * @Last Modified time: 2019-08-16 23:30:32 */ // #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include #include #include #include #include #include #include #include #include #include <string> #include #include #include #include #include #include #include #include #include <set> #include // #include // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<#define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair pll; typedef pair p3; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; template inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ mt19937 rnd(time(0)); const int maxn = 1e4+9; struct E { int u,v,w; }edge[maxn]; int col[maxn]; int n,m,k; ll dp[maxn][70]; ll randgao() { for(int i=1; i<=n; i++) col[i] = rnd() % k; for(int i=1; i<=n; i++){ for(int j=0; j<(1 << k) ; j++) { dp[i][j] = -inff; } int j = (1 << col[i]); dp[i][j] = 0; } for(int j = 0; j < (1 << k) ; j++ ) { for(int i=1; i<=m; i++) { int u = edge[i].u, v = edge[i].v, w = edge[i].w; if((j & (1 << col[u]))) dp[u][j] = max(dp[u][j], dp[v][j ^ (1 << col[u])] + w); if((j & (1 << col[v]))) dp[v][j] = max(dp[v][j], dp[u][j ^ (1 << col[v])] + w); } } int up = (1 << k) - 1; ll res = -inff; for(int i=1; i<=n; i++) res = max(res, dp[i][up]); return res == -inff ? -1 : res; } int main(){ int T; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &m, &k); for(int i=1; i<=m; i++) { scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w); } ll ans = -1; for(int rep = 1; rep <= 300; rep++){ ans = max(ans, randgao()); } if(ans == -1) puts("impossible"); else printf("%lld\n", ans); } return 0; }