1. 程式人生 > >虛樹(Bzoj3611: [Heoi2014]大工程)

虛樹(Bzoj3611: [Heoi2014]大工程)

c++ type mem 方便 deep 工程 amp pri ret

題面

傳送門

虛樹

把跟詢問有關的點拿出來建樹,為了方便樹\(DP\)
\(LCA\)處要合並答案,那麽把這些點的\(LCA\)也拿出來

做法:把點按\(dfs\)序排列,然後求出相鄰兩個點的\(LCA\),把這些點建一個虛樹,維護一個棧就好了

Sol

虛樹+樹\(DP\)

# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

IL int
Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } const
int maxn(1e6 + 5); const int inf(1e9); int n, first1[maxn], cnt, first2[maxn], id[maxn], p[maxn]; ll g[maxn], f[maxn], num[maxn], sum, mx, mn, tot; int dfn[maxn], size[maxn], son[maxn], fa[maxn]; int s[maxn], top[maxn], idx, deep[maxn]; struct Edge{ int to, next; } e2[maxn << 1], e1[maxn << 1
]; IL void Add1(RG int u, RG int v){ e1[cnt] = (Edge){v, first1[u]}, first1[u] = cnt++; } IL void Add2(RG int u, RG int v){ e2[cnt] = (Edge){v, first2[u]}, first2[u] = cnt++; } IL void Dfs1(RG int u){ size[u] = 1; for(RG int e = first1[u]; e != -1; e = e1[e].next){ RG int v = e1[e].to; if(!size[v]){ deep[v] = deep[u] + 1; Dfs1(v), size[u] += size[v], fa[v] = u; if(size[v] > size[son[u]]) son[u] = v; } } } IL void Dfs2(RG int u, RG int tp){ top[u] = tp, dfn[u] = ++idx; if(son[u]) Dfs2(son[u], tp); for(RG int e = first1[u]; e != -1; e = e1[e].next) if(!dfn[e1[e].to]) Dfs2(e1[e].to, e1[e].to); } IL int LCA(RG int u, RG int v){ while(top[u] ^ top[v]) deep[top[u]] > deep[top[v]] ? u = fa[top[u]] : v = fa[top[v]]; return deep[u] > deep[v] ? v : u; } IL int Dis(RG int u, RG int v){ RG int lca = LCA(u, v); return deep[u] + deep[v] - 2 * deep[lca]; } IL int Cmp(RG int u, RG int v){ return dfn[u] < dfn[v]; } IL void DP(RG int u){ g[u] = inf, f[u] = -inf; if(num[u]) g[u] = f[u] = 0; for(RG int e = first2[u]; e != -1; e = e2[e].next){ RG int v = e2[e].to, w = Dis(u, v); DP(v), num[u] += num[v]; sum += (tot - num[v]) * num[v] * w; mn = min(mn, g[u] + w + g[v]); mx = max(mx, f[u] + w + f[v]); g[u] = min(g[u], g[v] + w); f[u] = max(f[u], f[v] + w); } } int main(){ n = Input(); for(RG int i = 1; i <= n; ++i) first1[i] = first2[i] = -1; for(RG int i = 1; i < n; ++i){ RG int u = Input(), v = Input(); Add1(u, v), Add1(v, u); } Dfs1(1), Dfs2(1, 1); for(RG int q = Input(); q; --q){ RG int k = Input(); cnt = 0, tot = k; for(RG int i = 1; i <= k; ++i) p[i] = Input(), num[p[i]] = 1; sort(p + 1, p + k + 1, Cmp); for(RG int i = 1, t = k; i < t; ++i) p[++k] = LCA(p[i], p[i + 1]); sort(p + 1, p + k + 1, Cmp), k = unique(p + 1, p + k + 1) - p - 1; for(RG int i = 1; i <= k; ++i) first2[p[i]] = -1; RG int t = 0; for(RG int i = 1; i <= k; ++i){ while(t && dfn[p[i]] >= dfn[s[t]] + size[s[t]]) --t; if(t) Add2(s[t], p[i]); s[++t] = p[i]; } mx = sum = 0, mn = inf; DP(p[1]); printf("%lld %lld %lld\n", sum, mn, mx); for(RG int i = 1; i <= k; ++i) num[p[i]] = 0; } return 0; }

虛樹(Bzoj3611: [Heoi2014]大工程)