[BZOJ3611][HEOI2014]大工程(虚树+树形DP)
来源:互联网 发布:优化职能 编辑:程序博客网 时间:2024/05/19 19:44
看到这样的问题,还是先构建出虚树。以下
对于求最短距离和最长距离,实际上就类似于求最短链和最长链的问题,记一个最小(大)值和一个次小(大)值进行DP求出。
求边权和,记
以上四个值可以一遍DFS算出。
那么可以得出,LCA为
LCA为
由于点对
此题细节较多。
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}typedef long long ll;const int N = 1e6 + 5, M = 2e6 + 5, LogN = 22, INF = 0x3f3f3f3f;int n, ecnt, nxt[M], adj[N], go[M], dep[N], fa[N][LogN], vir[N], vn, stk[N],par[N], vdn, dfn[N], times, aux[N], ecnt2, nxt2[M], adj2[N], go2[M],Max, Min, sze[N], maxd[N], mind[N]; ll sum, deps[N], dsum[N], dcnt[N];bool isvir[N];void add_edge(int u, int v) { nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;}void add_edge2(int u, int v) { nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v;}void dfs(int u, int fu) { int i; dep[u] = dep[fa[u][0] = fu] + 1; dfn[u] = ++times; for (i = 0; i <= 19; i++) fa[u][i + 1] = fa[fa[u][i]][i]; for (int e = adj[u], v; e; e = nxt[e]) if ((v = go[e]) != fu) dfs(v, u);}int lca(int u, int v) { int i; if (dep[u] < dep[v]) swap(u, v); for (i = 20; i >= 0; i--) { if (dep[fa[u][i]] >= dep[v]) u = fa[u][i]; if (u == v) return u; } for (i = 20; i >= 0; i--) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0];}bool comp(int u, int v) { return dfn[u] < dfn[v];}void build() { int i, top = 0; vdn = vn; sort(vir + 1, vir + vn + 1, comp); for (i = 1; i <= vdn; i++) { int u = vir[i]; if (!top) {par[stk[++top] = u] = 0; continue;} int w = lca(stk[top], u); while (dep[stk[top]] > dep[w]) { if (dep[stk[top - 1]] < dep[w]) par[stk[top]] = w; top--; } if (w != stk[top]) vir[++vn] = w, par[w] = stk[top], stk[++top] = w; par[stk[++top] = u] = w; } sort(vir + 1, vir + vn + 1, comp); ecnt2 = 0; for (i = 1; i <= vn; i++) adj2[vir[i]] = 0; for (i = 2; i <= vn; i++) add_edge2(par[vir[i]], vir[i]);}void dfs2(int u, int fu) { sze[u] = isvir[u]; ll ds, dc; deps[u] = isvir[u] ? dep[u] : 0; maxd[u] = -INF; mind[u] = INF; int nmax = -INF, nmin = INF; for (int e = adj2[u], v; e; e = nxt2[e]) dfs2(v = go2[e], u), sze[u] += sze[v], deps[u] += deps[v]; ds = dsum[u] = 1ll * (sze[u] - 1) * deps[u]; dc = dcnt[u] = 1ll * sze[u] * (sze[u] - 1) >> 1; for (int e = adj2[u], v; e; e = nxt2[e]) { dc -= dcnt[v = go2[e]]; ds -= dsum[v]; if (maxd[v] > maxd[u]) nmax = maxd[u], maxd[u] = maxd[v]; else if (maxd[v] > nmax) nmax = maxd[v]; if (mind[v] < mind[u]) nmin = mind[u], mind[u] = mind[v]; else if (mind[v] < nmin) nmin = mind[v]; } sum += ds - dc * dep[u] * 2; if (maxd[u] != -INF && nmax != -INF) Max = max(Max, maxd[u] + nmax - dep[u] * 2); if (mind[u] != INF && nmin != INF) Min = min(Min, mind[u] + nmin - dep[u] * 2); if (isvir[u]) { Max = max(Max, maxd[u] - dep[u]); Min = min(Min, mind[u] - dep[u]); maxd[u] = max(maxd[u], dep[u]); mind[u] = min(mind[u], dep[u]); }}int main() { int i, x, y, q; n = read(); for (i = 1; i < n; i++) x = read(), y = read(), add_edge(x, y); dfs(1, 0); q = read(); while (q--) { vdn = vn = read(); for (i = 1; i <= vn; i++) isvir[aux[i] = vir[i] = read()] = 1; sum = 0; Max = -INF; Min = INF; build(); dfs2(vir[1], 0); printf("%lld %d %d\n", sum, Min, Max); for (i = 1; i <= vdn; i++) isvir[aux[i]] = 0; } return 0;}
阅读全文
0 0
- bzoj3611: [Heoi2014]大工程 虚树+树形dp
- [BZOJ3611][Heoi2014]大工程(虚树+树形dp)
- [BZOJ3611][HEOI2014]大工程(虚树+树形DP)
- 【bzoj3611】[Heoi2014]大工程 虚树+dp
- [BZOJ3611][Heoi2014]大工程 虚树+dp
- [虚树] BZOJ3611: [Heoi2014]大工程
- bzoj3611: [Heoi2014]大工程
- [BZOJ3611] [Heoi2014]大工程
- bzoj3611: [Heoi2014]大工程
- bzoj3611 [Heoi2014]大工程
- 【HEOI2014】bzoj3611 大工程
- 3611: [Heoi2014]大工程|树形DP|虚树
- bzoj 3611: [Heoi2014]大工程 (虚树+树形DP)
- bzoj 3611: [Heoi2014]大工程(虚树+树形DP)
- 【bzoj3611】【大工程】【虚树+dp】
- bzoj 3611: [Heoi2014]大工程 虚树+树形dp
- 【BZOJ 3611】[Heoi2014]大工程 虚树+树形dp
- BZOJ3611——[Heoi2014]大工程
- android 数字和字母 检测
- [BZOJ2298][HAOI2011]problem a(DP)
- C51计数器
- 大数据开发源码视频今日免费送!
- PAT (Advanced Level) Practise 1008. Elevator (20)
- [BZOJ3611][HEOI2014]大工程(虚树+树形DP)
- Java线程池
- 机器学习的思路
- linux增加su也即root的PATH
- vscode跨设备同步配置失败问题。
- [BZOJ2004][HNOI2010]公交线路(状压DP+矩阵乘法)
- 戴尔笔记本机械硬盘换成固态硬盘,重装系统后进不去系统,开机提示operating system not found的解决办法
- [BZOJ2243][SDOI2011]染色(树剖+线段树)
- Kotlin基础笔记