CH#56C 异象石
一道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 异象石的更多相关文章
- CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏
异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...
- [bzoj1912]异象石(set)
Description Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上有N个点,有N-1条双向边把它们连 ...
- Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】
期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目 ...
- [LOJ#10132]异象石
Description Adera 是 Microsoft 应用商店中的一款解谜游戏. 异象石是进入 Adera 中异时空的引导物,在 Adera 的异时空中有一张地图.这张地图上 有 N 个点,有 ...
- CH#56C(LCA+dfs序)
题目传送门 性质是:把节点dfs序以后,异象石按这个序号排序,然后相邻两两求树上距离,这些距离的和除以二就是最小斯坦纳树. 插入删除的具体操作是根据我们上述性质,用一个set维护dfn,比如插入x,则 ...
- LOJ #10132. 「一本通 4.4 例 3」异象石
题目地址 LOJ 题解 神仙思路.思路参考自<算法竞赛进阶指南>. 考虑维护dfs序中相邻两个石头的距离,那么每次?的答案就是sum/2(首尾算相邻) 然后维护一下拿个平衡树/set维护一 ...
- lca:异象石(set+dfs序)
题目:https://loj.ac/problem/10132 #include<bits/stdc++.h> using namespace std; ,N,k=,head[]; str ...
- 蓝皮书:异象石 【dfs序+lca】
题目详见蓝皮书[算法竞赛:进阶指南]. 题目大意: 就是给你一颗树,然后我们要在上面进行三种操作: 1.标记某个点 或者 2.撤销某个点的标记 以及 3.询问标记点在树上连通所需的最短总边 ...
- 异象石(就是sdio宝藏那题)
题解: 之前这道题写过两次题解了吧.. 实现的时候可以用set<int,cmp>来实现按照dfn排序 代码: 感觉别人的分类讨论比我的简单.. 但我觉得我这个写起来也不烦就不看别人的了.. ...
随机推荐
- python字典dict的成对运算
dict = {'age': 18, 'name': 'jin', 'sex': 'male', }# for k,v in dict.items():# print(k,v)# v1 = dict[ ...
- BeanFactory的实现原理
先来看看Java代码获取Spring中Bean的代码(一共有五种方式,这里只展示其中一种方法): 有没有发现上面的代码与利用反射实现工厂模式的代码很相似.对,你没有看错,Spring中的BeanFac ...
- kafka 删除topic清空数据
原 kafka 删除topic清空数据 2018年11月20日 18:17:50 Ming! 阅读数:1391 版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...
- 通过网址request到response经历的过程
前言当我们在浏览器中输入一个网址,比如www.google.cn,浏览器就会加载出百度的主页.那么浏览器背后完成的具体是怎么样的呢? 总结起来大概的流程是这样的: (1)浏览器本身是一个客户端,当你输 ...
- matlab 矩阵拼接
E=[a,b]%水平方向上的拼接 E=[a :b] %垂直方向上的拼接
- 线段树模板(HDU 6356 Glad You Came)
题目: HDU 6356 http://acm.hdu.edu.cn/showproblem.php?pid=6356 很裸的线段树 #include<bits/stdc++.h> #de ...
- 带轮播图、导航栏、商品的简单html,以及轮播图下边数字随轮播图的改变而改变
---恢复内容开始--- 在做这个的时候,最不会的是中间轮播图下边的数字是如何实现转变的,后来加入了jQuery就能实现了. css部分: <style type="text/css& ...
- 预览InputFile
[预览InputFile] 通过input的files属性,可以取到选择的File对象,通过FileReader可以将File对象读取出来. <body> <input type=& ...
- destructuring assignment
[destructuring assignment] The destructuring assignment syntax is a JavaScript expression that makes ...
- 使用fckeditor上传多张图片
流程: 1.使用fck上传图片到后台 2.后台上传图片到服务器端 3.服务器端返回上传信息 1.jsp页面 <script type="text/javascript"> ...