洛谷 P3320: bzoj 3991: LOJ 2182: [SDOI2015]寻宝游戏
题目传送门: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]寻宝游戏的更多相关文章
- 洛谷 P5206: bzoj 5475: LOJ 2983: [WC2019] 数树
		
一道技巧性非常强的计数题,历年WC出得最好(同时可能是比较简单)的题目之一. 题目传送门:洛谷P5206. 题意简述: 给定 \(n, y\). 一张图有 \(|V| = n\) 个点.对于两棵树 \ ...
 - 洛谷 P1129 BZOJ 1059 cogs 660 [ZJOI2007]矩阵游戏
		
题目描述 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作: 行交 ...
 - bzoj 3991: [SDOI2015]寻宝游戏 虚树 set
		
目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...
 - P3320 [SDOI2015]寻宝游戏 解题报告
		
P3320 [SDOI2015]寻宝游戏 题目描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有\(N\)个村庄和\(N-1\)条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以 ...
 - 3991: [SDOI2015]寻宝游戏
		
3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...
 - P3320 [SDOI2015]寻宝游戏
		
题目 P3320 [SDOI2015]寻宝游戏 做法 很巧妙的一种思路,懂了之后觉得大水题 首先要知道:在一棵树上标记一些点,然后从任意一点出发,遍历所有的的最小路径为\(dfs\)序从小到大遍历 那 ...
 - 【LG3320】[SDOI2015]寻宝游戏
		
[LG3320][SDOI2015]寻宝游戏 题面 洛谷 题解 不需要建虚树的虚树2333... 贪心地想一下,起始节点肯定是在关键点上,访问顺序就是\(dfs\)序. 那么对于每次询问, \[ An ...
 - CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏
		
异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...
 - [BZOJ3991][SDOI2015]寻宝游戏
		
[BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...
 
随机推荐
- 【Alpha】第三次Scrum meeting
			
今日任务一览: 导航栏诞生 前期准备的Latex文本将撰写完毕 生成燃尽图的问题已经解决 姓名 今日完成任务 所耗时间 刘乾 用Github成功生成了燃尽图(真是不容易啊...),与架构师继续每日面基 ...
 - 《Linux内核分析》课程第二周学习总结
			
姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
 - 20135234mqy-——信息安全系统设计基础第十三周学习总结
			
第十一章 网络编程 11.1 客户端-服务器编程模型 基本操作:事务 当一个客户端需要服务时,向服务器发送一个请求,发起一个事务. 服务器收到请求后,解释它,并以适当的方式操作它的资源. 服务器给客户 ...
 - 查询过的问题关于HTML的问题
			
一.Bootstrap字体图标(Glyphicons) http://www.runoob.com/bootstrap/bootstrap-glyphicons.html 二.Jquery 实现 “下 ...
 - Linux shell(1)
			
Linux的Shell种类众多,常见的有:Bourne Shell(/usr/bin/sh或/bin/sh).Bourne Again Shell(/bin/bash).C Shell(/usr/bi ...
 - Github作为图床的一个小坑
			
Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...
 - We are a team----sh_6666
			
团队宣言:编程,我们是玩命的,玩命,我们是认真的. 团队简介: 团队名称:sh_6666队 团队博客链接:http://www.cnblogs.com/sh-6666/ 人物简介: 剧团导演:吴小勇 ...
 - Xcode常见设置
			
1.设置主题和字体大小
 - pixi.js v5 快速了解
			
pixi.js 追求简单, 性能,高价值. pixi.js v5将是一交比较大的升级,代码更加精简,性能更加强悍,功能更加丰富,扩展更加高效 pixi.js一步一脚印,版本持续稳定的更新, 深入学习 ...
 - TRichEdit怎样新增的内容到最后一行?
			
Delphi里使用TRichEdit,使用SetSelTextBuf时可以设置显示的字体格式,但是显示位置是在当前的插入光标后,如果人为改变插入光标的位置,比如在其他位置单,以后再插入的内容位置就没办 ...