Luogu 3320 [SDOI2015]寻宝游戏
一开始还真没想到。
发现从所有有宝藏的点出发绕一圈只要不刻意绕路答案都是一样的,即我们呢要求的最后答案$ans = dis(x_1, x_2) + dis(x_2, x_3) +... + dis(x_{k - 1}, x_k) + dis(x_k, x_1)$。
不刻意绕远路怎么办呢,我们把有宝藏的点按照$dfs$序,维护一个有序的$set$就可以了。
每次插入就相当于找到一个点$x$在$dfs$序中的前一个点$lst$和后一个点$nxt$,使最后的答案减去$dis(nxt, lst)$并加上$dis(x, nxt) + dis(lst, x)$,删除同理。
我选择用倍增来求$dis(x, y)$。
$set$的细节一开始没想清楚,写了一会儿。
时间复杂度$O(nlogn)$。
Code:
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
typedef long long ll; const int N = 1e5 + ;
const int Lg = ; int n, qn, tot = , head[N];
int dep[N], fa[N][Lg], dfsc = , id[N], mp[N];
ll ans = 0LL, dis[N];
bool ex[N];
set <int> s; struct Edge {
int to, nxt;
ll val;
} e[N << ]; inline void add(int from, int to, ll val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} void dfs(int x, int fat, int depth, ll nowDis) {
fa[x][] = fat, dep[x] = depth, dis[x] = nowDis;
id[x] = ++dfsc, mp[id[x]] = x;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + , nowDis + e[i].val);
}
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} inline int getLca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][];
} inline ll getDis(int x, int y) {
int z = getLca(x, y);
return dis[x] + dis[y] - * dis[z];
} int main() {
read(n), read(qn);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
ll v; read(v);
add(x, y, v), add(y, x, v);
}
dfs(, , , 0LL); /* for(int i = 1; i <= n; i++)
printf("%d ", id[i]);
printf("\n"); */ for(int x, cnt = ; qn--; ) {
read(x);
if(!ex[x]) {
ex[x] = ;
s.insert(id[x]);
++cnt;
if(cnt == ) {
puts("");
continue;
}
set <int> :: iterator it = s.find(id[x]), it2 = it;
if(it == s.begin()) it = s.end();
int lst = *(--it);
it = s.find(id[x]);
int nxt = ;
if((++it2) == s.end()) nxt = *(s.begin());
else nxt = *(++it);
ans += getDis(mp[lst], x) + getDis(mp[nxt], x) - getDis(mp[lst], mp[nxt]);
} else {
ex[x] = ;
--cnt;
if(cnt == ) {
puts("");
s.erase(id[x]);
continue;
}
set <int> :: iterator it = s.find(id[x]), it2 = it;
if(it == s.begin()) it = s.end();
int lst = *(--it);
it = s.find(id[x]);
int nxt = ;
if((++it2) == s.end()) nxt = *(s.begin());
else nxt = *(++it);
ans -= getDis(mp[lst], x) + getDis(mp[nxt], x) - getDis(mp[lst], mp[nxt]);
s.erase(id[x]);
}
printf("%lld\n", ans);
} return ;
}
Luogu 3320 [SDOI2015]寻宝游戏的更多相关文章
- Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】
期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目 ...
- luogu P3320 [SDOI2015]寻宝游戏
大意:给定树, 要求维护一个集合, 支持增删点, 询问从集合中任取一点作为起点, 遍历完其他点后原路返回的最短长度. 集合中的点按$dfs$序排列后, 最短距离就为$dis(s_1,s_2)+...+ ...
- 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)
被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...
- [BZOJ3991][SDOI2015]寻宝游戏
[BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...
- bzoj 3991: [SDOI2015]寻宝游戏 虚树 set
目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...
- P3320 [SDOI2015]寻宝游戏 解题报告
P3320 [SDOI2015]寻宝游戏 题目描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有\(N\)个村庄和\(N-1\)条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以 ...
- 【LG3320】[SDOI2015]寻宝游戏
[LG3320][SDOI2015]寻宝游戏 题面 洛谷 题解 不需要建虚树的虚树2333... 贪心地想一下,起始节点肯定是在关键点上,访问顺序就是\(dfs\)序. 那么对于每次询问, \[ An ...
- 3991: [SDOI2015]寻宝游戏
3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...
- 【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set
[BZOJ3991][SDOI2015]寻宝游戏 Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩 ...
随机推荐
- P1393 动态逆序对
题目 P1393 动态逆序对 做题前写篇博客是个好方法 做法 题目规定仅有删除,给每个位置标个号,逆序对+时间轴,显然这是个三维偏序 很久没做过\(cdq\)了,就当模板题讲一下: 按删除的先后顺序为 ...
- 深入理解JVM - 晚期(运行期)优化
在部分商用虚拟机中,Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或者代码块的运行特别频繁时,就会把这些代码认定为“热点代码”(Hot Spot Code) ...
- (转)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date ...
- [深入学习C#]C#实现多线程的方法:线程(Thread类)和线程池(ThreadPool)
简介 使用线程的主要原因:应用程序中一些操作需要消耗一定的时间,比如对文件.数据库.网络的访问等等,而我们不希望用户一直等待到操作结束,而是在此同时可以进行一些其他的操作. 这就可以使用线程来实现. ...
- BEC listen and translation exercise 36
你所持的护照可使你享有免费医疗.Your passport qualifies you to receive free medical treatment.公司指使其职员挖对手的客户.The comp ...
- QWidget上下文菜单处理函数
QWidget类是Qt中所有可视化部件的基类,其很多函数都是虚函数,能被子类重写以表现不同形式和功能,今天来学习一下QWdiget的事件处理函数. 事件是鼠标.键盘或系统因其自身某些状态发生改变而引起 ...
- codeforces 598C C. Nearest vectors(极角排序)
题目链接: C. Nearest vectors time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- hdu-5640 King's Cake (水题)
题目链接 King's Cake Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...
- stl_set.h
stl_set.h // Filename: stl_set.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: http://blo ...
- 制作SD卡img文件,并扩容
/********************************************************************************** * raspi-config E ...