bzoj 3572[HNOI2014]世界树
来源:互联网 发布:大数据技术相关书籍 编辑:程序博客网 时间:2024/06/05 09:13
欢迎点此阅读QvQ
Descripiton
给定一棵树,有若干个询问,每次给定
Solution
一个很经典的题,通过这题学到了一个叫虚树的东西,修为得到的精进
虚树就是包含了给定点,并收缩了不分叉边的连通子图
然后我们讨论下虚树的构建
先给代码
void build(int m) { int top = 0; sort(h + 1, h + m + 1, cmp); for (int i = 1; i <= m; ++i) { if (!top) fa[st[++top] = h[i]] = 0; else { int x = lca(st[top], h[i]); for (; dep[st[top]] > dep[x]; --top) if (dep[st[top - 1]] <= dep[x]) fa[st[top]] = x; if (st[top] != x) { fa[x] = st[top]; t[++tot] = st[++top] = x; near[x] = mp(0x3f3f3f3f, 0); } fa[st[++top] = h[i]] = x; } }}
我们将给定点按lca递增排序,用一个栈表示已构建的虚树上以最后一个点为断点的链,设栈顶元素为p,当前点为x,然后我们求出lca
有两种情况
* (1):
* (2):
对于第二种情况,由于
对于第一种情况,由于
由于
然后就可以继续把当前x加入栈中,继续处理这条链,代码很短,但是需要理解一会~
容易发现构建的虚树最多
构建完虚树就是树形dp的事情了,先按
继续按dfs序递增处理
如果是虚树的根,那么首先对管理它的点的贡献就是
假设当前点是
否则考虑尽量靠中间的点,分奇偶讨论下即可
Code
#include <bits/stdc++.h>//虚树using namespace std;#define pb push_back#define mp make_pair#define F first#define S secondtypedef long long LL;typedef pair<int, int> pii;const int N = 3e5 + 5;vector<int> g[N];pii near[N];int n, tot, ind, dep[N], dfn[N], sz[N], f[N][20], pos[N], h[N], t[N], st[N], fa[N], w[N], dis[N], ans[N];bool cmp(const int &x, const int &y) { return dfn[x] < dfn[y];}int find(int x, int d) { for (int i = 19; i >= 0; --i) if (dep[f[x][i]] >= d) x = f[x][i]; return x;}int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (int i = 19; i >= 0; --i) if (dep[f[x][i]] >= dep[y]) x = f[x][i]; if (x == y) return x; for (int i = 19; i >= 0; --i) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0];}void dfs(int u) { sz[u] = 1; dfn[u] = ++ind; for (int i = 0, v; i < g[u].size(); ++i) { v = g[u][i]; if (v == f[u][0]) continue; f[v][0] = u; for (int j = 1; j <= 19; ++j) f[v][j] = f[f[v][j - 1]][j - 1]; dep[v] = dep[u] + 1; dfs(v); sz[u] += sz[v]; }}void build(int m) { int top = 0; sort(h + 1, h + m + 1, cmp); for (int i = 1; i <= m; ++i) { if (!top) fa[st[++top] = h[i]] = 0; else { int x = lca(st[top], h[i]); for (; dep[st[top]] > dep[x]; --top) if (dep[st[top - 1]] <= dep[x]) fa[st[top]] = x; if (st[top] != x) { fa[x] = st[top]; t[++tot] = st[++top] = x; near[x] = mp(0x3f3f3f3f, 0); } fa[st[++top] = h[i]] = x; } }}void work() { tot = 0; int m; scanf("%d", &m); for (int i = 1; i <= m; ++i) { scanf("%d", &h[i]); t[++tot] = pos[i] = h[i], ans[h[i]] = 0, near[h[i]] = mp(0, h[i]); } build(m); sort(t + 1, t + tot + 1, cmp); for (int i = 1; i <= tot; ++i) { int x = t[i]; w[x] = sz[x]; if (i > 1) dis[x] = dep[x] - dep[fa[x]]; } for (int i = tot; i > 1; --i) { int x = t[i]; near[fa[x]] = min(near[fa[x]], mp(near[x].F + dis[x], near[x].S)); } for (int i = 2; i <= tot; ++i) { int x = t[i]; near[x] = min(near[x], mp(near[fa[x]].F + dis[x], near[fa[x]].S)); } for (int i = 1; i <= tot; ++i) { int x = t[i]; if (i == 1) ans[near[x].S] += n - sz[x]; else { int rt = find(x, dep[fa[x]] + 1); int sum = sz[rt] - sz[x]; w[fa[x]] -= sz[rt]; if (near[fa[x]].S == near[x].S) ans[near[x].S] += sum; else { int mid = dep[x] - (near[fa[x]].F - near[x].F + dis[x]) / 2; if ((near[fa[x]].F + near[x].F + dis[x]) % 2 == 0 && near[fa[x]].S < near[x].S) ++mid; int tmp = sz[find(x, mid)] - sz[x]; ans[near[fa[x]].S] += sum - tmp; ans[near[x].S] += tmp; } } } for (int i = 1; i <= tot; ++i) ans[near[t[i]].S] += w[t[i]]; for (int i = 1; i <= m; ++i) printf("%d ", ans[pos[i]]); puts("");}void gao() { scanf("%d", &n); for (int i = 1, u, v; i < n; ++i) { scanf("%d%d", &u, &v); g[u].pb(v), g[v].pb(u); } dfs(dep[1] = 1); int q; scanf("%d", &q); while (q--) work();}int main() { gao(); return 0;}
- bzoj 3572[HNOI2014]世界树
- BZOJ 3572: [Hnoi2014]世界树
- bzoj 3572: [Hnoi2014]世界树
- 【BZOJ】3572: [Hnoi2014]世界树【虚树DP】
- bzoj 3572 [Hnoi2014]世界树 虚树 dp
- BZOJ 3572 [Hnoi2014]世界树 虚树
- 虚树(bzoj 3572: [Hnoi2014]世界树)
- 3572: [Hnoi2014]世界树
- bzoj 3572 [Hnoi2014]世界树(虚树+DP)
- bzoj 3572: [Hnoi2014]世界树 (虚树+树形DP+LCA)
- 3572: [Hnoi2014]世界树 虚树+DP
- bzoj3572: [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- [BZOJ3572][HNOI2014]世界树
- [BZOJ3572] [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- [bzoj3572][HNOI2014]世界树
- 【Android】设置EditText为仅输入数字且最多只能有两位数字
- DataTable 修改列名 删除列 调整列顺序
- 动态修改UINavigationBar的背景色
- JNA调用C语言动态链接库学习实践总结(指针模拟)
- AndroidIO编程
- bzoj 3572[HNOI2014]世界树
- PHP mysql 两个数据库的表连接查询
- 我与大话设计模式之代码篇(三)---抽象工厂模式
- UITextField点击textField外任意区域键盘回收(二)---- TouchesBegan
- LightOJ 1047 - Neighbor House(DP)
- 虚拟机linux与主机时间同步
- 二维数组运算符重载
- cron表达式详解
- HTTP服务器响应状态信息