【动态点分】绿老师 解题报告
来源:互联网 发布:魏晨退出非凡搭档 知乎 编辑:程序博客网 时间:2024/04/28 17:58
题目来源:2017北京八十中集训12.4考试题。出题人hhd
p.s. 这题有个dfs做法。但鉴于我从未写过动态点分,wxh佬建议我拿这道题练一下,作为我的第一道动态点分模板题。
Introduction
在线求树上最远点对
树有边权,给出
如果是单次询问,当然可以dfs求直径
或者静态点分单次
最好用动态点分,可以在线带修,
对于一个点,把它插入到点分树上所有祖先中(包括它自己)。对于另一个点,查询点它分树上所有祖先的信息来更新答案。再保证一下查询到不在同一子树的解(即每个点分中心维护来自不同子树的最大值和次大值),就可以保证每两个点都恰好在点分树的LCA处被查到一次。
因此我们可以动态支持同时插入和查询。
BZOJ1095 [ZJOI2007] 捉迷藏
参考链接:https://www.cnblogs.com/zzqsblog/p/6393023.html
一棵树,每个点有一个颜色(黑或白),一开始全是黑色。修改是将某个点的颜色反转,询问黑点间的最长距离。
简要题解
这是公认的动态点分模板题。
询问时,仍然是每个点分中心找到不在同一子树中的最大值和次大值来更新答案。
这道题就是上面那道简单题加上删除操作。因为最大值可能被删掉,可以用可删除的堆来维护最大值。
在每个点开两个堆,第一个堆维护这个中心管辖的所有黑点到中心的距离,第二个堆维护所有分治儿子的堆顶。注意如果分治树上的重心是白点,那么不应该用单独一个来更新答案,如果只用一个黑点来更新答案是不合法的。为了统计答案,我们显然还要再开一个堆来维护答案。
修改就只要沿着点分治树往根走,维护一下经过的祖先节点的堆即可。
Solution
绿老师把这个最远点对的问题扩展到二维。
基本思路仍然是每次点分统计跨过中心的答案。
当然只能对
比如我们对
需要注意的是点分的复杂度保证在于
对于一个点分中心,把它的前
综上,这是个静态点分套动态点分。先把点分树建出来,然后再开一个静态点分,内套动态点分求答案。
Debug
第一次写出了两个bug
bug #1
最开始时,我记fa[]
为点分树上的父亲,dis[]
为到fa
的距离。
WA掉样例后发现一个点到其点分树祖先的距离不一定等于点分树上链dis
求和,这个距离应该在原树上跑dfs来求。
因此要开dis[200000][18]
来分别记录它到所有(dis[][]
数组。
bug #2
测了一次80分,发现WA了“
注意到点分中心对应的一堆
Code
#include <cstdio>#include <vector>#define INF 9000000000000000LLtypedef long long ll;typedef std::vector<int> vec;inline void Max(ll &a, ll b) { if (a < b) a = b; }int n, m;vec b[100050];int h[100050], nx[200050], to[200050], e = 1;ll w[200050];inline void adde(int u, int v, ll d) { to[e] = v; w[e] = d; nx[e] = h[u]; h[u] = e++;}bool vis[100050];int sz[100050], mx[100050], hv[100050];int dfssize(int x, int f) { sz[x] = b[x].size() + 1; mx[x] = 0; for (int i = h[x]; i; i = nx[i]) if (!vis[to[i]] && to[i] != f) { register int ret = dfssize(to[i], x); sz[x] += ret; if (ret > mx[x]) { mx[x] = ret; hv[x] = i; } } return sz[x];}int root;int fa[100050][18], cnt[100050];ll dis[100050][18];vec son[100050];void setroot(int u, int f, ll d) { fa[u][cnt[u]] = root; dis[u][cnt[u]++] = d; for (int i = h[u]; i; i = nx[i]) if (!vis[to[i]] && to[i] ^ f) setroot(to[i], u, d + w[i]);}void divide(int u, int f) { int Size = dfssize(u, f); while (mx[u] > Size>>1) u = to[hv[u]]; setroot(root = u, u, 0); vis[u] = true; son[f].push_back(u); for (int i = h[u]; i; i = nx[i]) if (!vis[to[i]]) divide(to[i], u);}ll ans = 0;ll d1[100050], d2[100050];int g[100050];void insert(int x, int f, ll d) { for (int i = h[x]; i; i = nx[i]) if (vis[to[i]] && to[i] ^ f) insert(to[i], x, d + w[i]); for (int u : b[x]) for (int i = 0; i < cnt[u]; i++) { register int p = fa[u][i], q = fa[u][i+1]; register ll v = d + dis[u][i]; if (v > d1[p]) { if (q ^ g[p]) d2[p] = d1[p], g[p] = q; d1[p] = v; } else if (v > d2[p] && q ^ g[p]) d2[p] = v; }}void query(int x, int f, ll d) { for (int i = h[x]; i; i = nx[i]) if (vis[to[i]] && to[i] ^ f) query(to[i], x, d + w[i]); for (int u : b[x]) for (int i = 0; i < cnt[u]; i++) Max(ans, (fa[u][i+1] ^ g[fa[u][i]] ? d1 : d2)[fa[u][i]] + d + dis[u][i]);}void clear(int x, int f) { for (int i = h[x]; i; i = nx[i]) if (vis[to[i]] && to[i] ^ f) clear(to[i], x); for (int u : b[x]) for (int i = cnt[u]-1, p; i >= 0 && ~g[p = fa[u][i]]; i--) d1[p] = d2[p] = -INF, g[p] = -1;}void solve(int x) { for (int i = h[x]; i; i = nx[i]) if (vis[to[i]]) { query(to[i], x, w[i]); insert(to[i], x, w[i]); } for (int u : b[x]) for (int i = 0; i < cnt[u]; i++) { register int p = fa[u][i], q = fa[u][i+1]; register ll v = dis[u][i]; Max(ans, (q ^ g[p] ? d1 : d2)[p] + v); if (v > d1[p]) { if (q ^ g[p]) d2[p] = d1[p], g[p] = q; d1[p] = v; } else if (v > d2[p] && q ^ g[p]) d2[p] = v; } clear(x,0); vis[x] = false; for (int nx : son[x]) solve(nx);}int main() { freopen("forgive.in","r",stdin); freopen("forgive.out","w",stdout); scanf("%d%d",&n,&m); int u, v; ll w; for (int i = 1; i < n; i++) { scanf("%d%d%lld",&u,&v,&w); adde(u,v,w); adde(v,u,w); } while (m--) { scanf("%d%d",&u,&v); b[u].push_back(v); } divide(1,0); clear(1,0); solve(son[0][0]); printf("%lld\n",ans); return 0;}
- 【动态点分】绿老师 解题报告
- 解题报告(2)——动态分班
- 朋友 (30分) 解题报告
- 藏尾诗 (15分) 解题报告
- 监控 (30分) 解题报告
- 动态树 解题报告
- 算24点 解题报告
- 连接格点 解题报告
- 1163 动态规划 解题报告
- zoj2770解题报告(差分约束)
- 差分约束POJ1201NIntervals解题报告
- 查分约束POJ3169Layout解题报告
- POJ3169 差分约束系统 解题报告
- 九宫格输入法 (25分) 解题报告
- 灯 塔 (30分) 解题报告
- Hdu 1529 差分约束 解题报告
- Cdoj 24点游戏之解题报告
- Poj 1741 Tree 点分治 解题报告
- Android 两个Activity之间相互跳转传值 并且关闭之前的Activity
- [DP] HDU 1029
- cocos环境搭建
- 动态内存管理
- struts2+spring+mybatis datagrid增删改查以及分页的实现
- 【动态点分】绿老师 解题报告
- JavaScript学习-封装基础库3
- 用两个线程玩猜数字游戏,第一个线程负责随机给出1~100之间的一个整数,第二个线程负责猜出这个数。
- Python 标准库
- Elasticserach6.x之Head插件安装-yellowcong
- springmvc基础-1
- 洛谷P2234 [HNOI2002]营业额统计_Treap
- 读入输出优化
- java中final关键字测试总结