一道LCA

原题链接

先跑一边\(dfs\),求出每个节点的时间戳,如果我们将有异象石的节点按时间戳从小到大的顺序排列,累加相邻两节点之间的距离(首尾相邻),会发现总和就是答案的两倍。

于是我们只需要维护这个按时间戳排序的有序数列和答案即可。

当插入一个新的节点\(u\)时,设插入位置的原有两节点为\(x,y\),\(dis(x,y)\)表示两节点间的距离,那么只需要将答案减去\(dis(x,y)\),再加上\(dis(x,u)+dis(u,y)\)即可,删除则类似。

而为了快速求\(dis(x,y)\),我们可以先用\(dfs\)求出\(d[x]\),表示从节点\(x\)到根的距离,于是\(dis(x,y)=d[x]+d[y]-2\times d[LCA(x,y)]\),\(LCA\)使用倍增法求即可。

至于维护有序数列,我们可用\(C++\ STL\ set\)来维护。

不过因为我平时\(STL\)用的比较少,这题也是我第一次用\(set\)及迭代器,所以代码可能写的比较鬼畜(尤其是迭代器部分又臭又长)。。

#include<cstdio>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
struct dd {
int x, t;
bool operator < (const dd &b)const
{
return t < b.t;
}
};
dd o, X, Y;
int fi[N], ne[N << 1], di[N << 1], da[N << 1], f[N][18], de[N], ti[N], l, gn, T, n;
ll dis[N];
set<dd>S;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c<'0' || c>'9'; c = getchar())
p |= c == '-';
for (; c >= '0'&&c <= '9'; c = getchar())
x = x * 10 + (c - '0');
return p ? -x : x;
}
inline int re_l()
{
char c = getchar();
for (; c != '+'&&c != '-'&&c != '?'; c = getchar());
return c == '+' ? 1 : (c == '-' ? 2 : 0);
}
inline void sw(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
void dfs(int x)
{
int i, y;
ti[x] = ++T;
for (i = 1; i <= gn; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for (i = fi[x]; i; i = ne[i])
{
y = di[i];
if (!de[y])
{
de[y] = de[x] + 1;
dis[y] = dis[x] + da[i];
f[y][0] = x;
dfs(y);
}
}
}
int lca(int x, int y)
{
int i;
if (de[x] > de[y])
sw(x, y);
for (i = gn; ~i; i--)
if (de[f[y][i]] >= de[x])
y = f[y][i];
if (!(x^y))
return x;
for (i = gn; ~i; i--)
if (f[x][i] ^ f[y][i])
{
x = f[x][i];
y = f[y][i];
}
return f[x][0];
}
ll calc(int x, int y)
{
return dis[x] + dis[y] - (dis[lca(x, y)] << 1);
}
int main()
{
int i, m, x, y, z, si = 0;
ll s = 0;
n = re();
gn = log2(n);
for (i = 1; i < n; i++)
{
x = re();
y = re();
z = re();
add(x, y, z);
add(y, x, z);
}
de[1] = 1;
dfs(1);
m = re();
for (i = 1; i <= m; i++)
{
x = re_l();
if (!x)
printf("%lld\n", s >> 1);
else
{
o.x = re();
o.t = ti[o.x];
if (!(x ^ 1))
{
if (!si)
{
S.insert(o);
si++;
continue;
}
if (!(si ^ 1))
{
S.insert(o);
si++;
set<dd>::iterator it = S.find(o);
it == --S.end() ? Y = *S.begin() : Y = *--S.end();
s += calc(o.x, Y.x) << 1;
continue;
}
si++;
S.insert(o);
set<dd>::iterator fk, it = S.find(o);
fk = it;
it == --S.end() ? Y = *S.begin() : Y = *++it;
fk == S.begin() ? X = *--S.end() : X = *--fk;
s -= calc(X.x, Y.x);
s += calc(X.x, o.x);
s += calc(Y.x, o.x);
}
else
{
if (!(si ^ 2) || !(si ^ 1))
{
si--;
s = 0;
S.erase(o);
continue;
}
si--;
set<dd>::iterator fk, it = S.find(o);
fk = it;
it == --S.end() ? Y = *S.begin() : Y = *++it;
fk == S.begin() ? X = *--S.end() : X = *--fk;
S.erase(o);
s -= calc(X.x, o.x);
s -= calc(Y.x, o.x);
s += calc(X.x, Y.x);
}
}
}
return 0;
}

CH#56C 异象石的更多相关文章

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

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

  2. [bzoj1912]异象石(set)

    Description Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上有N个点,有N-1条双向边把它们连 ...

  3. Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】

    期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目 ...

  4. [LOJ#10132]异象石

    Description Adera 是 Microsoft 应用商店中的一款解谜游戏. 异象石是进入 Adera 中异时空的引导物,在 Adera 的异时空中有一张地图.这张地图上 有 N 个点,有 ...

  5. CH#56C(LCA+dfs序)

    题目传送门 性质是:把节点dfs序以后,异象石按这个序号排序,然后相邻两两求树上距离,这些距离的和除以二就是最小斯坦纳树. 插入删除的具体操作是根据我们上述性质,用一个set维护dfn,比如插入x,则 ...

  6. LOJ #10132. 「一本通 4.4 例 3」异象石

    题目地址 LOJ 题解 神仙思路.思路参考自<算法竞赛进阶指南>. 考虑维护dfs序中相邻两个石头的距离,那么每次?的答案就是sum/2(首尾算相邻) 然后维护一下拿个平衡树/set维护一 ...

  7. lca:异象石(set+dfs序)

    题目:https://loj.ac/problem/10132 #include<bits/stdc++.h> using namespace std; ,N,k=,head[]; str ...

  8. 蓝皮书:异象石 【dfs序+lca】

    题目详见蓝皮书[算法竞赛:进阶指南]. 题目大意: 就是给你一颗树,然后我们要在上面进行三种操作:  1.标记某个点  或者  2.撤销某个点的标记  以及   3.询问标记点在树上连通所需的最短总边 ...

  9. 异象石(就是sdio宝藏那题)

    题解: 之前这道题写过两次题解了吧.. 实现的时候可以用set<int,cmp>来实现按照dfn排序 代码: 感觉别人的分类讨论比我的简单.. 但我觉得我这个写起来也不烦就不看别人的了.. ...

随机推荐

  1. python 稀疏向量和矩阵的表示形式

    http://blog.csdn.net/nkwangjie/article/details/17502443 http://blog.csdn.net/bitcarmanlee/article/de ...

  2. 消息中间件MQ详解及四大MQ比较

    一.消息中间件相关知识 1.概述 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流 ...

  3. gradle 很好用的么

    Gradle 其实是很好用的 2017, Apr 14 by Tesla Ice Zhang Gradle 是一款使用 Kotlin (划掉) Groovy 编写的 JVM 构建工具,其易用性和 Ma ...

  4. 以root用户运行jenkins中shell命令 重要

    以centOS系统为例,记录下修改Jenkins以root用户运行的方法. 修改Jenkins配置文件 # 打开配置文件vim /etc/sysconfig/jenkins# 修改$JENKINS_U ...

  5. vue-cli结构介绍

    vue-cli是vue项目开发的脚手架,非常方便,其结构大致如下, 其中static是存放静态资源的,存放的静态数据可以访问到,如果在static文件夹中创建mock文件夹,在mock文件夹中创建in ...

  6. video 播放本地视屏

    var file = document.getElementById('file_video').files[0]; var url = URL.createObjectURL(file); docu ...

  7. Opengl库函数列表

    http://www.cnblogs.com/GameDeveloper/archive/2012/01/07/2315867.html

  8. 测试工具之appcrawler的使用

    appcrawler 标签(空格分隔): appcrawler appcrawler 简介 一个基于自动遍历的app爬虫工具. 支持android和iOS, 支持真机和模拟器. 最大的特点是灵活性. ...

  9. jvisual修改内存大小

    jvisual(Java VisualVM)导入dump文件内存不足解决办法: 当通过jvusual调整-Xmx参数: c:/program files/java/jdk1.6/lib/visualv ...

  10. Oracle的regexp_instr函数简单用法

    REGEXP_INSTR函数让你搜索一个正则表达式模式字符串.函数使用输入字符集定义的字符进行字符串的计算. 它返回一个整数,指示开始或结束匹配的子位置,这取决于return_option参数的值. ...