传送门:>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. 内网IP外网IP的关联及访问互联网原理

    首先解释一下“内网”与“外网”的概念: 内网:即所说的局域网,比如学校的局域网,局域网内每台计算机的IP地址在本局域网内具有互异性,是不可重复的.但两个局域网内的内网IP可以有相同的. 外网:即互联网 ...

  2. Jenkins- job之间传参

    前言: 本文介绍插件: Parameterized Trigger plugin的具体使用方法. 一.插件介绍 Parameterized Trigger plugin插件可以让你在构建完成时触发新的 ...

  3. Alpha冲刺阶段评分发布

    一班 二班 三班  四班

  4. oc之脚本

    进入Build Phases页面,点击加号选择“New Run Script Phases”创建Run Script 在这里添加Run Script, 1.每次编译运行版本号(bundleVersio ...

  5. 分析一个react项目

    目录结构 下面是使用npx create-react-app web-app来创建的一个项目(已经删除了多余的文件) web-app ├── node_modules │   ├── ....... ...

  6. semantic-ui 模态窗口

    模态窗口即加了ui modal的class的div而已,会有点像是alert弹出框的形式,但是美观一点点.

  7. Python&R&量化 金融之路

    [ 分类 ]- 金融之路 - 闲云孤鹤(人生在世五十年,大千世界一瞬间,浮生若梦,仿佛间,幻境一场,生者无常,终须尽.) - CSDN博客 https://blog.csdn.net/robertso ...

  8. js创建并下载文件

    先上代码: function createAndDownloadFile(fileName, content) { var aTag = document.createElement('a'); va ...

  9. laravel 循环中子元素使用&符号嵌入到父级,经典版

    /**ajax 获取企业名称 * * @param Request $request * * @return \Illuminate\Http\JsonResponse * @author lxw * ...

  10. JS对象、基本类型和字面量的区别

    字面值: var str1='this is a simple string'; var num1=1.45; var answer1=true; 基本类型: var str2=String('thi ...