题目传送门: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. 第二阶段团队冲刺——One

    个人任务: 司宇航:处理第一次启动服务器500的问题. 季方:优化cookie第一次运行出错的问题. 王金萱:修改注册界面. 马佳慧:修改登录界面. 站立会议: 任务看板和燃尽图:

  2. Oracle 标准版 企业版 个人版的区别 转帖

    转帖来源: https://blog.csdn.net/flg_inwind/article/details/2628133 同事方总:http://www.oracle.com/us/corpora ...

  3. layout图形化界面看不到内容 Failed to find the style corresponding to the id

    1.问题 在创建新的工程的时候,选择目标SDK为api21,编译SDK为api23.创建出来的layout文件图形化界面中看不到,并且报错: Failed to find the style corr ...

  4. Python的文件读写

    目录 读文件 操作文件 读取内容 面试题的例子 写文件 操作模式 指针操作 字符编码 读文件 操作文件 打开一个文件用open()方法(open()返回一个文件对象,它是可迭代的): 文件使用完毕后必 ...

  5. 深入理解Vue的生命周期

    谈到Vue的生命周期,相信许多人并不陌生.但大部分人和我一样,只是听过而已,具体用在哪,怎么用,却不知道.我在学习vue一个多礼拜后,感觉现在还停留在初级阶段,对于mounted这个挂载还不是很清楚. ...

  6. BZOJ 3170 松鼠聚会(切比雪夫距离转曼哈顿距离)

    题意 有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1.现在N个松鼠要走到一个松鼠家去,求走过的最短距离. 思路 题目 ...

  7. 安装配置ubuntu的web项目(新)

    1.下载jre wget -c javadl.oracle.com/webapps/download/AutoDL?BundleId=211989 -O jre-8u101-linux-i586.ta ...

  8. JavaFile类和递归

    八.File类和递归 8.1 概述 java.io.File 类时文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和产出等操作. 8.2 构造方法 public File(String pa ...

  9. 编译nginx平滑添加stream模块

    1.操作背景 操作系统版本:CentOS Linux release (Core) nginx版本:1.13.4 nginx从1.9.0版本开始,新增了ngx_stream_core_module模块 ...

  10. MT【80】单调性求函数表达式

    提示:$f(f(f(x)-lnx)-ln(f(x)-lnx))=1+e=f(f(x)-lnx),\because f(x)$单调.得: $f(f(x)-lnx)-ln(f(x)-lnx)=f(x)-l ...