题目大意:

一颗树 有一个点的集合

对于每个集合的答案为 从集合内一个点遍历集合内所有点再返回的距离最小值

每次可以选择一个点 若在集合外便加入集合 若在集合内就删除

求每次操作后这个集合的答案

思路:

对于每个集合

它的答案一定为从dfs序最小的开始依次遍历再回来

当加入一个点x的时候 可以找到它dfs序的前驱与后继 画图可得 ans+=dis(pre,x)+dis(x,sub)-dis(pre,sub)  删除的时候为ans-=

特别地 当x没有前驱或后继时 前驱为最大值 后继为最小值(当做一个环

因此我们维护一颗平衡树搞一下即可

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#define inf 2139062143
#define ll long long
#define MAXN 100100
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int ch[MAXN][],fa[MAXN],sz,cnt[MAXN],val[MAXN],size[MAXN],rt;
int which(int x) {return x==ch[fa[x]][];}
int find_pre()
{
int pos=ch[rt][];
while(ch[pos][]) pos=ch[pos][];
return pos;
}
int find_max()
{
int pos=ch[rt][];
while(ch[pos][]) pos=ch[pos][];
return pos;
}
int find_min()
{
int pos=ch[rt][];
while(ch[pos][]) pos=ch[pos][];
return pos;
}
int find_sub()
{
int pos=ch[rt][];
while(ch[pos][]) pos=ch[pos][];
return pos;
}
void upd(int x)
{
if(!x) return ;
size[x]=cnt[x]+size[ch[x][]]+size[ch[x][]];
}
void rotate(int pos)
{
int f=fa[pos],ff=fa[f],k=which(pos);
ch[f][k]=ch[pos][k^],fa[ch[f][k]]=f,fa[f]=pos,ch[pos][k^]=f,fa[pos]=ff;
if(ff) ch[ff][ch[ff][]==f]=pos;
upd(f);upd(pos);
}
void splay(int x)
{
for(int f;f=fa[x];rotate(x))
if(fa[f]) rotate((which(x)==which(f)?f:x));
rt=x;
}
void Insert(int x)
{
int pos=rt,f=;
while()
{
if(val[pos]==x) {cnt[pos]++,upd(pos);upd(f);splay(pos);return ;}
f=pos,pos=ch[pos][x>val[pos]];
if(!pos)
{
ch[++sz][]=ch[sz][]=,fa[sz]=f,val[sz]=x,cnt[sz]=size[sz]=,ch[f][x>val[f]]=sz;
upd(f);splay(sz);return ;
}
}
}
void insert(int x)
{
if(!rt) {val[++sz]=x,ch[sz][]=ch[sz][]=fa[sz]=,cnt[sz]=size[sz]=,rt=sz;return;}
Insert(x);
}
int find_rank(int x)
{
int res=,pos=rt;
while()
{
if(x<val[pos]) pos=ch[pos][];
else
{
res+=size[ch[pos][]];
if(val[pos]==x) {splay(pos);return res+;}
res+=cnt[pos],pos=ch[pos][];
}
}
}
void dlt(int x)
{
if(cnt[rt]>) {cnt[rt]--;return ;}
if(!ch[rt][]&&!ch[rt][]) {rt=;return ;}
if(!ch[rt][]||!ch[rt][])
{
int k=!ch[rt][]?:;
rt=ch[rt][k],fa[rt]=;
return ;
}
int k=find_pre(),tmp=rt;
splay(k);fa[ch[tmp][]]=rt;
ch[rt][]=ch[tmp][],rt=k;
}
int n,m,nxt[MAXN<<],fst[MAXN],to[MAXN<<],Val[MAXN<<],Cnt;
int f[MAXN][],dep[MAXN],s[MAXN],k[MAXN],tot,hsh[MAXN],HSH[MAXN],vis[MAXN];
ll ans,dis[MAXN];
void add(int u,int v,int w) {nxt[++Cnt]=fst[u],fst[u]=Cnt,to[Cnt]=v,Val[Cnt]=w;}
void dfs(int x)
{
for(int i=;(<<i)<=dep[x];i++) f[x][i]=f[f[x][i-]][i-];
hsh[x]=++tot,HSH[tot]=x;
for(int i=fst[x];i;i=nxt[i])
if(to[i]!=f[x][])
{
dis[to[i]]=dis[x]+Val[i],dep[to[i]]=dep[x]+;
f[to[i]][]=x;dfs(to[i]);
}
}
int lca(int u,int v)
{
int t;
if(dep[u]<dep[v]) swap(u,v);
t=dep[u]-dep[v];
for(int i=;i<;i++)
if((<<i)&t) u=f[u][i];
if(u==v) return u;
for(int i=;i>=;i--)
if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][];
}
inline ll calc(int u,int v) {return dis[HSH[u]]+dis[HSH[v]]-(dis[lca(HSH[u],HSH[v])]<<);}
int main()
{
n=read(),m=read();int a,b,c;
for(int i=;i<n;i++) {a=read(),b=read(),c=read();add(a,b,c);add(b,a,c);}
dfs();
while(m--)
{
c=hsh[read()],vis[c]^=;
if(vis[c])
{
if(!rt) {puts("");insert(c);continue;}insert(c);
a=val[find_pre()],b=val[find_sub()];
if(!a) a=val[find_max()];if(!b) b=val[find_min()];
if(!a) a=val[rt];if(!b) b=val[rt];
ans+=calc(a,c)+calc(b,c)-calc(a,b);
}
else
{
a=find_rank(c);
a=val[find_pre()],b=val[find_sub()];
if(!a) a=val[find_max()];if(!b) b=val[find_min()];
if(!a) a=val[rt];if(!b) b=val[rt];
ans-=calc(a,c)+calc(b,c)-calc(a,b);
dlt(c);
}
printf("%lld\n",ans);
}
}

bzoj 3991 寻宝游戏的更多相关文章

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

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

  2. 【BZOJ】【3991】【SDOI2015】寻宝游戏

    dfs序 我哭啊……这题在考试的时候(我不是山东的,CH大法吼)没想出来……只写了50分的暴力QAQ 而且苦逼的写的比正解还长……我骗点分容易吗QAQ 骗分做法: 1.$n,m\leq 1000$: ...

  3. 树形结构的维护:BZOJ 3991: [SDOI2015]寻宝游戏

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

  4. bzoj 3991: [SDOI2015]寻宝游戏

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

  5. 寻宝游戏(bzoj 3991)

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

  6. BZOJ 3991: [SDOI2015]寻宝游戏 树链的并+set

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

  7. [BZOJ 3991][SDOI2015]寻宝游戏(dfs序)

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

  8. BZOJ.5285.[AHOI/HNOI2018]寻宝游戏(思路 按位计算 基数排序..)

    BZOJ LOJ 洛谷 话说vae去年的专辑就叫寻宝游戏诶 只有我去搜Mystery Hunt和infinite corridor了吗... 同样按位考虑,假设\(m=1\). 我们要在一堆\(01\ ...

  9. 3991: [SDOI2015]寻宝游戏

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

随机推荐

  1. ZOJ 2478 Encoding

    Encoding Time Limit: 2 Seconds      Memory Limit: 65536 KB Given a string containing only 'A' - 'Z', ...

  2. 关于NSArray的去重

    提到去重,第一反应就是for或while循环来遍历处理. 然后有了几种思路: 1) 两个循环嵌套 对比 然后去重: 但是这种方法会数据丢失, arr为要去重的数组 ; i<arr.count; ...

  3. idea与eclipse项目相互导入的过程

    idea项目导出到桌面 很简单,直接去项目所在目录考出即可,但是考出的项目往往都特别大,这是因为考出之前  我们不要忘记把idea的输出目录删除 每次启动服务器运行idea项目的时候  都会有一个输出 ...

  4. 【HDOJ6300】Triangle Partition(极角排序)

    题意:给定3n个点,保证没有三点共线,要求找到一组点的分组方案使得它们组成的三角形之间互不相交. n<=1e3 思路:以y为第一关键字,x为第二关键字,按x递减,y递增排序 #include&l ...

  5. phpstorm的破解

    按照PHPstorm进入如下页面: 然后继续单击License  server  输入:http://www.0-php.com:1017    PHPstorm完美运行!!!!!

  6. 关于用String Calender类 计算闰年的Demo

    package cn.zmh.zuoye; import java.util.Calendar; public class StringRun { public static void main(St ...

  7. java基础 4 继承(1)访问权限与作用域

    作用域与可见性 当前类 同一package 子类 其他package public √ √ √ √ protected √ √ √   defalut √ √     private √      

  8. Java数组操作方法收集(快速判断某个值在这个数组中)

    Java数组操作最高效的方式是循环取值,如果转换成集合那么就会分配内存,效率不如前者,但是方法多,需要在性能调优上去权衡.切记:数组是数组,集合是集合. 下面是收集最常用的数组转成集合的操作方法: i ...

  9. Oracle Spatial中的空间索引

    转自cryolite原文 Oracle Spatial中的空间索引 Oracle Spatial可对空间数据进行R-tree索引,每个空间图层(Spatial Layer)的空间索引元信息都可以在US ...

  10. linux的shell的until循环举例说明

    执行脚本: sh login.sh user,其中user为第一个参数 如下所示,如果用户‘user’登录,'who | grep "$1"'为true,until循环结束,程序继 ...