题目传送门:LOJ #2182

题意简述:

一棵 \(n\) 个节点的树,边有边权。

每个点可能是关键点,每次操作改变一个点是否是关键点。

求所有关键点形成的极小联通子树的边权和的两倍。

题解:

有一个结论:DFS 序求出后,假设关键点按照 DFS 序排序后是 \(\{a_1,a_2,\ldots ,a_k\}\)。

那么所有关键点形成的极小联通子树的边权和的两倍等于 \(\mathrm{dist}(a_1,a_2)+\mathrm{dist}(a_2,a_3)+\cdots+\mathrm{dist}(a_{k-1},a_k)+\mathrm{dist}(a_k,a_1)\)。

画个图感性理解一下,应该是很好懂的。

那么求一下 DFS 序,每次操作相当于往集合里加入/删除一个元素。

假设插入 \(x\),它DFS序左右两边分别是 \(y\) 和 \(z\)。那么答案加上 \(\mathrm{dist}(x,y)+\mathrm{dist}(x,z)-\mathrm{dist}(y,z)\) 即可。

删除同理。还有,求 LCA 就用个倍增或者树剖吧,Tarjan 离线比较麻烦。

用 STL 自带的 set 容器维护起来很方便。你也可以手写树状数组/线段树/平衡树。

#include <cstdio>
#include <set> typedef long long LL;
const int MN = 100005; int N, M;
int h[MN], nxt[MN * 2], to[MN * 2], w[MN * 2], tot;
inline void ins(int x, int y, int z) {
nxt[++tot] = h[x], to[tot] = y, w[tot] = z, h[x] = tot;
} int dfn[MN], idf[MN], dfc;
int dep[MN], faz[MN][17];
LL dis[MN]; void DFS(int u, int fz) {
dfn[u] = ++dfc; idf[dfc] = u; dep[u] = dep[faz[u][0] = fz] + 1;
for (int j = 1; 1 << j < dep[u]; ++j) faz[u][j] = faz[faz[u][j - 1]][j - 1];
for (int i = h[u]; i; i = nxt[i]) if (to[i] != fz) dis[to[i]] = dis[u] + w[i], DFS(to[i], u);
} inline int lca(int x, int y) {
if (dep[x] < dep[y]) std::swap(x, y);
for (int d = dep[x] - dep[y], j = 0; d; d >>= 1, ++j)
if (d & 1) x = faz[x][j];
if (x == y) return x;
for (int j = 16; ~j; --j) if (faz[x][j] != faz[y][j])
x = faz[x][j], y = faz[y][j];
return faz[x][0];
} inline LL dist(int x, int y) { return dis[x] + dis[y] - 2 * dis[lca(x, y)]; } bool vis[MN];
std::set<int> st;
std::set<int>::iterator it;
LL Ans; int main() {
scanf("%d%d", &N, &M);
for (int i = 1, x, y, z; i < N; ++i) {
scanf("%d%d%d", &x, &y, &z);
ins(x, y, z), ins(y, x, z);
}
DFS(1, 0);
for (int m = 1, x, y, z; m <= M; ++m) {
scanf("%d", &x);
x = dfn[x];
if (!vis[idf[x]]) st.insert(x);
y = idf[(it = st.lower_bound(x)) == st.begin() ? *--st.end() : *--it];
z = idf[(it = st.upper_bound(x)) == st.end() ? *st.begin() : *it];
if (vis[idf[x]]) st.erase(x);
x = idf[x];
LL d = dist(x, y) + dist(x, z) - dist(y, z);
if (!vis[x]) vis[x] = 1, Ans += d;
else vis[x] = 0, Ans -= d;
printf("%lld\n", Ans);
}
return 0;
}

洛谷 P3320: bzoj 3991: LOJ 2182: [SDOI2015]寻宝游戏的更多相关文章

  1. 洛谷 P5206: bzoj 5475: LOJ 2983: [WC2019] 数树

    一道技巧性非常强的计数题,历年WC出得最好(同时可能是比较简单)的题目之一. 题目传送门:洛谷P5206. 题意简述: 给定 \(n, y\). 一张图有 \(|V| = n\) 个点.对于两棵树 \ ...

  2. 洛谷 P1129 BZOJ 1059 cogs 660 [ZJOI2007]矩阵游戏

    题目描述 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作: 行交 ...

  3. bzoj 3991: [SDOI2015]寻宝游戏 虚树 set

    目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...

  4. P3320 [SDOI2015]寻宝游戏 解题报告

    P3320 [SDOI2015]寻宝游戏 题目描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有\(N\)个村庄和\(N-1\)条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以 ...

  5. 3991: [SDOI2015]寻宝游戏

    3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...

  6. P3320 [SDOI2015]寻宝游戏

    题目 P3320 [SDOI2015]寻宝游戏 做法 很巧妙的一种思路,懂了之后觉得大水题 首先要知道:在一棵树上标记一些点,然后从任意一点出发,遍历所有的的最小路径为\(dfs\)序从小到大遍历 那 ...

  7. 【LG3320】[SDOI2015]寻宝游戏

    [LG3320][SDOI2015]寻宝游戏 题面 洛谷 题解 不需要建虚树的虚树2333... 贪心地想一下,起始节点肯定是在关键点上,访问顺序就是\(dfs\)序. 那么对于每次询问, \[ An ...

  8. CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏

    异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...

  9. [BZOJ3991][SDOI2015]寻宝游戏

    [BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...

随机推荐

  1. visual studio-2013之单元测试

    安装个vs把一个寝室搞得欲仙欲死的,,已经安装好了vs2013,那些欲仙欲死的事就都不说了.开始我们的正式作业——单元测试. 要做单元测试前提有: 1.要有Unit Test Generator工具 ...

  2. DOM之节点类型加例子

    DOM= Document Object Model,文档对象模型,DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构.换句话说,这是表示和处理一个HTML或XML文档的常用方法.D ...

  3. PHP 爬虫——QueryList

    前言: 来了个任务说要做个电影网站,要写个壳,数据直接从别人那扒.行吧!那就要学习下PHP爬虫了.占个博客,以后补充.http://study.querylist.cc/archives/6/ 之前开 ...

  4. final发布简评

    1.nice!——约跑app:本次发布使用摄像头展示,比之前清晰的多,展示效果很好,值得学习!功能都已实现,已经可以使用,好评. 2.飞天小女警——礼物挑选:本次发布风格与上次不同,除此之外添加了猜你 ...

  5. [转帖] 学习 Linux 大页的内存知识

    一.在解释什么情况下需要开启大页和为啥需要开启大页前先了解下Linux下页的相关的知识:以下的内容是基于32位的系统,4K的内存页大小做出的计算1)目录表,用来存放页表的位置,共包含1024个目录en ...

  6. obj.getClass() == Person.class 用于判断类型

    obj.getClass() == Person.class  用于判断类型

  7. [代码]--IIS发布网站浏览之后看到的是文件目录 & Internal Server Error 处理程序“ExtensionlessUrlHandler-ISAPI-4.0_64bit”在其模块列表中有一个错误模块“IsapiModule” 解决方法 & App_global.asax.pduxejp_.dll”--“拒绝访问。 ”

    Q:IIS发布网站浏览之后看到的是文件目录 A:它出现了一个说到.NET4.0 更高框架什么的错误,所以我将 .NTE CRL版本由4.0改为2.0了,改为2.0后就出现了只能浏览文件目录了.改为4. ...

  8. 【ARC082E】ConvexScore

    Description 给定二维直角坐标系上的N个点\((X_i,Y_i)\),定义一个有N个点中的部分点所构成点集为"凸点集",当且仅当该集合内的所有点恰好构成一个面积为正的凸多 ...

  9. CF1096D Easy Problem(DP)

    貌似最近刷了好多的CF题…… 题目链接:CF原网 洛谷 题目大意:有一个长度为 $n$ 的字符串 $s$,删除第 $i$ 个字符需要代价 $a_i$.问使得 $s$ 不含有子序列(不是子串)" ...

  10. 样本服从正态分布,证明样本容量n乘样本方差与总体方差之比服从卡方分布x^2(n)

    样本服从正态分布,证明样本容量n乘样本方差与总体方差之比服从卡方分布x^2(n) 正态分布的n阶中心矩参见: http://www.doc88.com/p-334742692198.html