[bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set
寻宝游戏 bzoj-3991 SDOI-2015
题目大意:题目链接。
注释:略。
想法:我们发现如果给定了一些点有宝物的话那么答案就是树链的并。
树链的并的求法就是把所有点按照$dfs$序排序然后相加再减去相邻之间的$lca$。
故此我们按照$dfs$序维护一个平衡树。
每次往里插入节点即可。
实时用$lca$更新答案,复杂度$O(nlogn)$。
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#define N 100010
using namespace std; typedef long long ll;
set<int>s;
int head[N],nxt[N<<1],to[N<<1],tot; ll val[N<<1];
ll dis[N],ans; int dic[N],f[22][N],size[N],re[N],dep[N],cnt;
bool vis[N];
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
ll rd() {ll x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline void add(int x,int y,ll z) {to[++tot]=y; val[tot]=z; nxt[tot]=head[x]; head[x]=tot;}
void dfs(int pos,int fa)
{
f[0][pos]=fa; for(int i=1;i<=20;i++) f[i][pos]=f[i-1][f[i-1][pos]];
dep[pos]=dep[fa]+1; dic[pos]=++cnt,re[cnt]=pos; size[pos]=1; for(int i=head[pos];i;i=nxt[i]) if(to[i]!=fa)
{
dis[to[i]]=dis[pos]+val[i]; dfs(to[i],pos); size[pos]+=size[to[i]];
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;~i;i--) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
if(x==y) return x;
for(int i=20;~i;i--) if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
inline void output()
{
set<int>::iterator it=s.begin();
for(;it!=s.end();it++) printf("%d ",*it); puts("");
}
int main()
{
int n=rd(),m=rd(); for(int i=1;i<n;i++) {int x=rd(),y=rd(); ll z=rd(); add(x,y,z); add(y,x,z);}
dfs(1,1);
// for(int i=1;i<=n;i++) printf("%d %d %d %d %d %d\n",re[dic[i]],dis[i],dic[i],dep[i],size[i],f[0][i]);
for(int i=1;i<=m;i++)
{
int x=rd();
if(s.empty()) {s.insert(dic[x]),ans=dis[x]; vis[x]=true;}
else if(!vis[x])
{
vis[x]=true;
set<int>::iterator it1=s.lower_bound(dic[x]);
set<int>::iterator it2=s.upper_bound(dic[x]);
if(it2==s.end())
{
it1--;
ans+=dis[x]-dis[lca(x,re[*it1])];
}
else
{
if(it1==s.begin()) ans+=dis[x]-dis[lca(x,re[*it1])];
else
{
it1--;
int y=re[*it1],z=re[*it2];
ans+=dis[x]+dis[lca(y,z)]-dis[lca(x,y)]-dis[lca(x,z)];
}
}
s.insert(dic[x]);
}
else
{
vis[x]=false;
set<int>::iterator it1=s.lower_bound(dic[x]);
set<int>::iterator it2=s.upper_bound(dic[x]);
if(it2==s.end())
{
if(it1==s.begin()) ans=0;
else
{
it1--;
int y=re[*it1];
ans+=dis[lca(x,y)]-dis[x];
}
}
else
{
if(it1==s.begin())
{
int z=re[*it2];
ans+=dis[lca(x,z)]-dis[x];
}
else
{
it1--;
int y=re[*it1],z=re[*it2];
ans+=dis[lca(y,x)]+dis[lca(x,z)]-dis[x]-dis[lca(y,z)];
}
}
s.erase(dic[x]);
}
// output();
// cout << ans << endl ;
set<int>::iterator it1=s.begin();
set<int>::iterator it2=s.end();
if(it1==it2) puts("0");
else
{
it2--;
if(it1==it2) puts("0");
else printf("%lld\n",(ans-dis[lca(re[*it1],re[*it2])])*2);
}
}
return 0;
}
小结:好题啊好题啊。
[bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set的更多相关文章
- [BZOJ3991][SDOI2015]寻宝游戏
[BZOJ3991][SDOI2015]寻宝游戏 试题描述 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择 ...
- CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏
异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...
- bzoj 3991: [SDOI2015]寻宝游戏 虚树 set
目录 题目链接 题解 代码 题目链接 bzoj 3991: [SDOI2015]寻宝游戏 题解 发现每次答案就是把虚树上的路径*2 接在同一关键点上的点的dfs序是相邻的 那么用set动态维护dfs序 ...
- bzoj3991 [Sdoi2015]寻宝游戏 set动态维护虚树+树链求并
题目大意:支持多次操作,增加或删除一个关键点 动态维护虚树边权和*2 分析:可以用树链求并的方法,最后减去虚树的根到1距离 注意到树链求并是所有点到根距离-所有dfn序相邻两点的LCA到根距离 找df ...
- bzoj3991 [SDOI2015]寻宝游戏 树链的并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3991 题解 貌似这个东西叫做树链的并,以前貌似写过一个类似的用来动态维护虚树. 大概就是最终的 ...
- BZOJ 3991: [SDOI2015]寻宝游戏 [虚树 树链的并 set]
传送门 题意: $n$个点的树,$m$次变动使得某个点有宝物或没宝物,询问每次变动后集齐所有宝物并返回原点的最小距离 转化成有根树,求树链的并... 两两树链求并就可以,但我们按照$dfs$序来两两求 ...
- BZOJ3991 [SDOI2015]寻宝游戏 【dfs序 + lca + STL】
题目 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路 ...
- 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set
[题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...
- 【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏
在考试代码的基础上稍微改改就a了……当时为什么不稍微多想想…… 插入/删除一个新节点时就把其dfn插入set/从set中删除. 当前的答案就是dfn上相邻的两两节点的距离和,再加上首尾节点的距离. 比 ...
随机推荐
- 深入学习数据结构之bitmap(四)
Bitmap,今天我们来分析一下bitmap的实现原理以及它的使用场景. 一.使用场景: 1.对于大量数据(几千个数据的就不要在废话了),且无重复或者可以忽略重复的数字.为啥这里要强调无重复,因为在b ...
- hihocoder1710 等差子数列
思路: 将数列合并之后使用线段树.边界条件容易写错. 实现: #include <bits/stdc++.h> using namespace std; ; const int INF = ...
- [SPOJ1812]Longest Common Substring II 后缀自动机 多个串的最长公共子串
题目链接:http://www.spoj.com/problems/LCS2/ 其实两个串的LCS会了,多个串的LCS也就差不多了. 我们先用一个串建立后缀自动机,然后其它的串在上面跑.跑的时候算出每 ...
- vba,excel,网址提取名字与链接url
'宏操作 Sub 复制超级链接() '这里控制读取A列的第1到10行,你根据自已的要求修改一下起始和结束行数 ).Hyperlinks.Count > ).Value = Cells(a, ). ...
- 虚拟机centOs Linux与Windows之间的文件传输
一.配置环境 虚拟机Linux:Fedora 9 文件传输工具:SSHSecureShellClient-3.2.9 二.实现步骤 1. 在Windows中安装文件传输工具SSHSecureShell ...
- MIUI类ROM如何正确修改dpi
(以下以MIUI为例) 在miui上,如果通过简单的修改build.prop会导致图标重绘错误,App图标分裂.此时配合一条简单的命令即可实现完美无bug的dpi修改. 1.使用终端模拟器执行su 2 ...
- 迅为4412全新升级版|3G开发板|4G开发板
iTOP-Exynos4412开发板采用 Exynos4412的主芯片,具有更高的主频和更丰富外设,配置 2GB 双通道 DDR3的内存及 16GB 存储,支持3G/G模块.GPS模块.陀螺仪.HDM ...
- PHP 之PHP + phantomJS实现网站截屏
php代码: exec("G:/phpstudy/WWW/destoon/api/a/cache/web/phantomjs.exe ./get.js http://www.baidu.co ...
- CAD参数绘制圆弧(com接口)
在CAD设计时,需要绘制圆弧,用户可以在图面点圆弧起点,圆弧上的一点和圆弧的终点,这样就绘制出圆弧. 主要用到函数说明: _DMxDrawX::DrawArc2 由圆弧上的三点绘制一个圆弧.详细说明如 ...
- Win10上 visual studio设置为本地IIS运行网站时 必须以管理员身份加载项目的解决方法
右键,选择“兼容性疑难解答”. 选择“疑难解答程序” 选择“该程序需要附加权限” 点击测试程序 点击下一步 选择 是,为此程序保存这些设置