标签:需要 span 输入 include 包括 getchar 获取 efi 研究
[BZOJ3677][Apio2014]连珠线
试题描述
输入
输出
输入示例
5 1 2 10 1 3 40 1 4 15 1 5 20
输出示例
60
数据规模及约定
数据范围满足1≤n≤200000。
题解
一个恶心至极的树形 dp。
我的做法大概是设状态为 f(i, j, k),i 表示我们在研究子树 i,其中 j 取 0 或 1;j = 0 时表示根在子树 i(注意这里的子树 i 都不包括节点 i)外,此时 k = 0 表示 i 不是中心点,k = 1 表示 i 是中心点;j = 1 时表示根在子树 i 中,此时 k = 0 表示 i 不是中心点,k = 1 表示 i 是中心点并且两条蓝边都在原树的子树 i 中,k = 2 表示 i 是中心点且有一条蓝边在原树的子树 i 中,另一条为 i 连向原树父亲的边。
这个 dp 不用换根,随便选一个点 rt 开始 dp 就好了,注意最后答案是 max{ f(rt, 0, 0), f(rt, 1, 0), f(rt, 1, 1) },没有 f(rt, 0, 1) 和 f(rt, 1, 2)(想一想为什么)。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); } return x * f; } #define maxn 200010 #define maxm 400010 #define oo (1ll << 50) #define LL long long int n, m, head[maxn], nxt[maxm], to[maxm], dist[maxm]; void AddEdge(int a, int b, int c) { to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m; swap(a, b); to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m; return ; } LL f[maxn][2][3]; void dp(int u, int fa) { LL sum = 0, m1x = -oo, m00 = -oo, m1x_1 = -oo, m1x_2 = -oo, m00_1 = -oo, m00_2 = -oo; int m1x_1id = -1, m00_1id = -1; bool has = 0; for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa) { has = 1; dp(to[e], u); LL tmp = max(f[to[e]][0][0], f[to[e]][0][1] > -oo ? f[to[e]][0][1] + dist[e] : 0); sum += tmp; if(f[to[e]][1][0] > -oo) m1x = max(m1x, max(max(f[to[e]][1][0], f[to[e]][1][1]), f[to[e]][1][2] + dist[e]) - tmp); m00 = max(m00, f[to[e]][0][0] - tmp); LL t1x = max(f[to[e]][1][0], f[to[e]][1][1]) + dist[e]; if(f[to[e]][1][0] > -oo) { if(t1x - tmp > m1x_1) m1x_2 = m1x_1, m1x_1 = t1x - tmp, m1x_1id = to[e]; else if(t1x - tmp > m1x_2) m1x_2 = t1x - tmp; } int t00 = f[to[e]][0][0] + dist[e]; if(t00 - tmp > m00_1) m00_2 = m00_1, m00_1 = t00 - tmp, m00_1id = to[e]; else if(t00 - tmp > m00_2) m00_2 = t00 - tmp; } if(!has) { f[u][0][1] = f[u][1][0] = f[u][1][1] = f[u][1][2] = -oo; return ; } f[u][0][0] = sum; if(m00_2 > -oo || fa) f[u][0][1] = sum + m00_1; f[u][1][0] = sum + max(m00, m1x); if(m00_2 > -oo) f[u][1][1] = sum + max(m00_1 + m00_2, max(m00_1 + (m00_1id == m1x_1id ? m1x_2 : m1x_1), m1x_1 + (m1x_1id == m00_1id ? m00_2 : m00_1))); if(fa) f[u][1][2] = sum + max(m00_1, m1x_1); // printf("%d: %d %d | %d %d %d\n", u, f[u][0][0], f[u][0][1], f[u][1][0], f[u][1][1], f[u][1][2]); return ; } int main() { n = read(); for(int i = 1; i < n; i++) { int a = read(), b = read(), c = read(); AddEdge(a, b, c); } dp(1, 0); printf("%d\n", (int)max(max(f[1][1][0], f[1][1][1]), f[1][0][0])); return 0; }
标签:需要 span 输入 include 包括 getchar 获取 efi 研究
原文地址:http://www.cnblogs.com/xiao-ju-ruo-xjr/p/6859831.html