一道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. SPSS-因子分析

    因子分析 有可能用较少的综合指标分析存在于各变量中的各类信息,而各综合指标之间彼此是不相关的,代表各类信息的综合指标称为因子.定义:因子分析就是用少数几个因子来描述许多指标或因素之间的联系,以较少几个 ...

  2. Python 第一个程序_1

    第一个Python程序(P108) 目标 第一个HelloPython 程序 Python2.x与3.x版本简介 执行Python程序的三种方式 解释器--python/python3  (终端中.使 ...

  3. MySQL 事务 隔离级别

    前两天面试,问到了四种隔离级别,当时觉得大多数数据库都为read committed,结果没想到mysql是个例外.在此做一下隔离级别和各种数据库锁的使用. 首先说一下ACID四大特性: 四大特性   ...

  4. cakePHP的ajax弹出窗

    在html里添加一个触发弹出框的按钮 $("#button1").on("click", function() { $("#dialogue" ...

  5. cdh 安装系列3--cdh manager 安装 cdh 6.01 版本

    安装前提是cdh manager 已经可以通过admin登录,管理台安装在192.168.20.163 一.安装自动TLS Setup Auto-TLS 1.ssh 192.168.20.163 2. ...

  6. tomcat端口被占用 实际上却查询不到此端口

    参考 http://www.cnblogs.com/jieliujas/p/9413064.html 1.打开PCHunter,在进程选项卡下面可以找到无法结束的进程,右键--强制结束,失败(这儿效果 ...

  7. 【selenium+python】关于使用selenium时的几个问题1

    问题:selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in ...

  8. 笔记-Python中逗号的作用

    1.用,去掉额外的换行符

  9. vue通过ID(参数)修改URL复用同一个页面(组件)不重新加载的问题

    项目中经常会用到同一个页面,结构是相同的,我只是在vue-router中通过添加参数的方式来区分状态,参数可以在页面跳转时带上params,或者query,但是有一个问题,即使我们修改了参数,URL也 ...

  10. RedHat 更新CentOS Yum源(转)

    经测试,可用.转自:https://www.cnblogs.com/tangsen/p/5151994.html 一.随笔引言 1.1随笔内容: 1.RedHat 配置Centos yum源 2.yu ...