传送门:>Here<

题意:给出一棵树(有边权),刚开始键值全部为0。每次对其中一个键值进行异或,问每一次修改之后:选择任意一个点出发走到所有为1的点再走回来的最短路

解题思路

由于N,M都是十万级别的,所以必须在线处理。很容易想到每次只需要对答案做出一点修改即可

考虑现在有$k$的节点有宝藏,那么假设他们共同在某一棵子树内,那么整棵树的其他部分根本不需要遍历到。因此我们需要找到这个子树的根,这个根就是目前所有节点的LCA。然后考虑从这个LCA出发开始走,总是会先走到DFS序较小的这样最优——因为DFS序比当前节点大只有两种情况:1.在当前节点的子树内 2.在当前节点的上面。对于第一种情况,显然可以免去走很多路,而对于第二种情况是无法避免的。

因此我们可以维护一个set,里面的元素是所有为1的点,并且按照DFS序从小到大排。为了让总路程最短,也就是让任意两个相邻的DFS序的元素之间的路程最短。因此我们的答案就是$Dis(set[1],set[2]) + Dis(set[2],set[3]) + ... + Dis(set[k-1],set[k]) + Dis(set[k],set[1])$。每一次插入一个元素,删除其相邻两点之间的$。事实上,由于从哪里出发要回到哪里,因此整个路径会形成一个环,所以从环上的任意一个点出发都是不会影响的。

每一次插入一个元素,删除其相邻两点之间的$Dis$,并且连接当前节点和相邻两个节点。删除同理。在set中可以采用lowerbound或者find函数。注意要特判边界情况

Code

如果lowerbound找到了end,意味着当前这个DFS是最大的,因此相邻的应该找打begin。找到start同理(昨天调试了两个小时……)

/*By DennyQi 2018.8.11*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <set>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = ;
const int MAXM = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) + (x << ) + c - '', c = getchar(); return x * w;
}
struct BaoZang{
int d,i;
};
bool operator < (const BaoZang& a, const BaoZang& b){
return a.d < b.d;
}
int N,M,x,y,ans,dfs_clock,w;
int first[MAXN<<],nxt[MAXN<<],to[MAXN<<],cost[MAXN<<],num_edge;
int dfn[MAXN],dep[MAXN],dis[MAXN],f[MAXN][],val[MAXN];
set <BaoZang> qxz;
inline void add(int u, int v, int w){
to[++num_edge] = v;
cost[num_edge] = w;
nxt[num_edge] = first[u];
first[u] = num_edge;
}
void DFS(int u, int _f, int d){
dfn[u] = ++dfs_clock;
dep[u] = d;
f[u][] = _f;
for(int i = ; (<<i) <= dep[u]; ++i){
f[u][i] = f[f[u][i-]][i-];
}
int v;
for(int i = first[u]; i; i = nxt[i]){
if((v = to[i]) == _f) continue;
dis[v] = dis[u] + cost[i];
DFS(v, u, d+);
}
}
inline int LCA(int a, int b){
if(dep[a] < dep[b]) swap(a, b);
for(int i = ; i >= ; --i){
if(dep[a] - (<<i) < dep[b]) continue;
a = f[a][i];
}
if(a == b) return a;
for(int i = ; i >= ; --i){
if(f[a][i] == f[b][i]) continue;
a = f[a][i], b = f[b][i];
}
return f[a][];
}
int main(){
// freopen(".in","r",stdin);
N = r, M = r;
for(int i = ; i < N; ++i){
x = r, y = r, w = r;
add(x, y, w);
add(y, x, w);
}
DFS(, , );
while(M--){
x = r;
if(qxz.size() == ){
val[x] = ;
qxz.insert((BaoZang){dfn[x],x});
printf("0\n");
continue;
}
if(!val[x]){
val[x] = ;
set<BaoZang>::iterator it = qxz.lower_bound((BaoZang){dfn[x], x});
if(it == qxz.end()){
it = qxz.begin();
}
set<BaoZang>::iterator it2;
if(it2 == qxz.begin()){
it2 = qxz.end();
--it;
}
else{
it2 = --it; ++it;
}
ans -= dis[it->i] + dis[it2->i] - * dis[LCA(it->i, it2->i)];
ans += dis[it->i] + dis[x] - * dis[LCA(it->i, x)];
ans += dis[x] + dis[it2->i] - * dis[LCA(x, it2->i)];
qxz.insert((BaoZang){dfn[x], x});
}
else{
val[x] = ;
set<BaoZang>::iterator it = qxz.find((BaoZang){dfn[x], x});
set<BaoZang>::iterator it1,it2;
if(it == qxz.begin()){
it1 = --qxz.end();
it2 = ++it; --it;
}
else if(it == --qxz.end()){
it1 = --it; ++it;
it2 = qxz.begin();
}
else{
it1 = --it; ++it;
it2 = ++it; --it;
}
ans += dis[it->i] + dis[it2->i] - * dis[LCA(it->i, it2->i)];
ans -= dis[it->i] + dis[x] - * dis[LCA(it->i, x)];
ans -= dis[x] + dis[it2->i] - * dis[LCA(x, it2->i)];
qxz.erase((BaoZang){dfn[x], x});
}
printf("%d\n", ans);
}
return ;
}

[SDOI2015] 寻宝游戏的更多相关文章

  1. [BZOJ3991][SDOI2015]寻宝游戏

    [BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...

  2. bzoj 3991: [SDOI2015]寻宝游戏 虚树 set

    目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...

  3. P3320 [SDOI2015]寻宝游戏 解题报告

    P3320 [SDOI2015]寻宝游戏 题目描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有\(N\)个村庄和\(N-1\)条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以 ...

  4. 【LG3320】[SDOI2015]寻宝游戏

    [LG3320][SDOI2015]寻宝游戏 题面 洛谷 题解 不需要建虚树的虚树2333... 贪心地想一下,起始节点肯定是在关键点上,访问顺序就是\(dfs\)序. 那么对于每次询问, \[ An ...

  5. 3991: [SDOI2015]寻宝游戏

    3991: [SDOI2015]寻宝游戏 https://www.lydsy.com/JudgeOnline/problem.php?id=3991 分析: 虚树+set. 要求树上许多点之间的路径的 ...

  6. 【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set

    [BZOJ3991][SDOI2015]寻宝游戏 Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩 ...

  7. P3320 [SDOI2015]寻宝游戏

    题目 P3320 [SDOI2015]寻宝游戏 做法 很巧妙的一种思路,懂了之后觉得大水题 首先要知道:在一棵树上标记一些点,然后从任意一点出发,遍历所有的的最小路径为\(dfs\)序从小到大遍历 那 ...

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

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

  9. [SDOI2015]寻宝游戏(LCA,set)

    [SDOI2015]寻宝游戏 题目描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到 ...

  10. [bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set

    寻宝游戏 bzoj-3991 SDOI-2015 题目大意:题目链接. 注释:略. 想法:我们发现如果给定了一些点有宝物的话那么答案就是树链的并. 树链的并的求法就是把所有点按照$dfs$序排序然后相 ...

随机推荐

  1. 五子棋(无AI winform gdi+)

    之前无意间在博客园看到一篇用深度学习玩马里奥的文章,于是就想做这个小东西来测试人工智能算法(准备用PYTHON的库,对神经网络的梦已经做了好多年了,但是太难了,一直懒得动它),本来是想用WPF做UI, ...

  2. Nginx 通过 Lua + Redis 实现动态封禁 IP

    一.背景 为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单.对于黑名单之内的 IP ,拒绝提供服务. 二.架构 实现 IP 黑名单的功能有很多途径: 1.在操作系统层面 ...

  3. 关于jsp中jstl-core标签循环遍历的使用

    JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能. JSTL支持通用的.结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签. 除了这些,它还提供 ...

  4. 便于记忆的SA构造

    首先学习基数排序. memset(b, 0, sizeof(b)); for(int i = 0; i < n; i++) b[a[i]]++; for(int i = 1; i <= m ...

  5. Python并发编程

    进程 相关概念 进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本 ...

  6. 输入input

    用input接收到的类型全部都是字符串!!! 要查看变量类型,可以使用type()模块: 字符串不能和数字进行比较,因此如果输入是以input方式输入的,需要先转换成数字格式:

  7. LINUX操作系统(centos6.9)安装与配置

    LINUX操作系统(centos6.9)安装与配置_百度经验 https://jingyan.baidu.com/article/acf728fd6bdba1f8e510a3f7.html cento ...

  8. react双组件传值和传参

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. laravel服务容器

    laravel框架底层解析 本文参考陈昊<Laravel框架关键技术解析>,搭建一个属于自己的简化版服务容器.其中涉及到反射.自动加载,还是需要去了解一下. laravel服务容器 建立项 ...

  10. Linux df 与du用法

    df 查看一级目录的大小,但是不能查看文件的大小.du 可以查看目录或者文件大小. 1 df的基本用法 df命令可以显示目前所有文件系统的总空间及当前可用空间,用法如下: -a 全部文件系统列表-h ...