题目链接

  其实这题用Set就完事了但我不会Set

  智商-=inf

  求虚树上所有边权和的两倍。

  具体方式就是splay把所有在虚树上的点存一下,(按照DFS序排序的)每次插入/删除会更新前驱和它、后继和它、前驱和后继的值

  

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#include<map>
#define maxn 200020
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} struct Splay{
struct Node{
int e[],fa;long long val,size;
}tree[maxn];
int root,tot;
Splay(){ root=tot=; }
inline int iden(int x){ return x==tree[tree[x].fa].e[]; }
inline void connect(int x,int fa,int how){ tree[x].fa=fa; tree[fa].e[how]=x; }
inline void update(int x){ tree[x].size=tree[tree[x].e[]].size+tree[tree[x].e[]].size+; }
void rotate(int x){
int y=tree[x].fa; int r=tree[y].fa;
int sony=iden(x); int sonr=iden(y);
if(root==y) root=x;
int b=tree[x].e[sony^];
connect(b,y,sony);
connect(y,x,sony^);
connect(x,r,sonr);
update(y); update(x);
}
void splay(int pos,int to){
to=tree[to].fa;
while(tree[pos].fa!=to){
if(tree[tree[pos].fa].fa==to) rotate(pos);
else
if(iden(tree[pos].fa)==iden(pos)){ rotate(tree[pos].fa),rotate(pos); }
else {rotate(pos),rotate(pos); }
}
}
inline int create(int fa,int val){
tree[++tot]=(Node){{,},fa,val,};
return tot;
}
inline int build(int val){
if(root==){
root=create(,val);
return root;
}
int now=root;
while(now){
tree[now].size++;
int nxt=val<tree[now].val?:;
if(tree[now].e[nxt]==){
connect(create(now,val),now,nxt);
return tot;
}
now=tree[now].e[nxt];
}
}
inline void insert(int val){
int p=build(val);
splay(p,root);
}
inline int find(int val){
int now=root;
while(now){
if(tree[now].val==val) return now;
int nxt=val<tree[now].val?:;
now=tree[now].e[nxt];
}
return ;
}
void dele(int x){
tree[x].e[]=tree[x].e[]=;
if(x==tot) tot--;
}
void pop(int val){
int now=find(val);
if(now==) return;
splay(now,root);
if(tree[now].e[]==){
root=tree[now].e[];
tree[root].fa=;
dele(now);
return;
}
int deal=tree[now].e[];
while(tree[deal].e[]) deal=tree[deal].e[];
splay(deal,tree[now].e[]);
connect(tree[now].e[],deal,);
root=deal; tree[deal].fa=;
update(deal);
dele(now);
return;
}
inline int lower(int val){
int now=root,ans=-0x7fffffff;
while(now){
if(tree[now].val<val&&tree[now].val>ans) ans=tree[now].val;
int nxt=val<tree[now].val?:;
now=tree[now].e[nxt];
}
return ans;
}
inline int upper(int val){
int now=root,ans=0x7fffffff;
while(now){
if(tree[now].val>val&&tree[now].val<ans) ans=tree[now].val;
int nxt=val<tree[now].val?:;
now=tree[now].e[nxt];
}
return ans;
}
}s; int d[maxn][];
long long w[maxn][];
int dfn[maxn],ID;
int deep[maxn];
bool ext[maxn];
int back[maxn];
long long dis[maxn]; struct Edge{
int next,to;
long long val;
}edge[maxn*];
int head[maxn],num;
inline void add(int from,int to,long long val){
edge[++num]=(Edge){head[from],to,val};
head[from]=num;
} void find(int x,int fa){
dfn[x]=++ID; back[ID]=x;
deep[x]=deep[fa]+;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(to==fa) continue;
dis[to]=dis[x]+edge[i].val;
d[to][]=x; w[to][]=edge[i].val;
find(to,x);
}
return;
} long long calcdis(int x,int y,int opt){
long long ans=;
if(deep[x]<deep[y]) swap(x,y);
int f=deep[x]-deep[y];
for(int i=;(<<i)<=f;++i)
if(f&(<<i)){
ans+=w[x][i];
x=d[x][i];
}
if(x==y) return opt==?ans:x;
for(int i=;i>=;--i){
if(d[x][i]==d[y][i]) continue;
ans+=w[x][i]+w[y][i];
x=d[x][i]; y=d[y][i];
}
return opt==?ans+w[x][]+w[y][]:d[x][];
} int main(){
int n=read(),m=read();
for(int i=;i<n;++i){
int from=read(),to=read(),val=read();
add(from,to,val);
add(to,from,val);
}
find(,);
for(int j=;j<=;++j)
for(int i=;i<=n;++i){
d[i][j]=d[d[i][j-]][j-];
w[i][j]=w[i][j-]+w[d[i][j-]][j-];
}
long long ans=;
while(m--){
int e=read();
int dfe=dfn[e];
if(ext[e]==){
ext[e]=;
int low=s.lower(dfe),upp=s.upper(dfe);
if(low>) ans+=calcdis(back[low],e,);
if(upp<=n) ans+=calcdis(back[upp],e,);
if(low>&&upp<=n) ans-=calcdis(back[low],back[upp],);
s.insert(dfe);
}
else{
ext[e]=;
s.pop(dfe);
int low=s.lower(dfe),upp=s.upper(dfe);
if(low>) ans-=calcdis(back[low],e,);
if(upp<=n) ans-=calcdis(back[upp],e,);
if(low>&&upp<=n) ans+=calcdis(back[low],back[upp],);
}
int last=s.lower(n+),first=s.upper();
long long ret=;
if(last>&&first<=n){ int lca=calcdis(back[last],back[first],);
ret=dis[back[last]]+dis[back[first]]-*dis[lca];
}
printf("%lld\n",ans+ret);
}
return ;
}

【Luogu】P3320寻宝游戏(Splay)的更多相关文章

  1. Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】

    期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目 ...

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

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

  3. P3320 [SDOI2015]寻宝游戏

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

  4. [洛谷P3320] SDOI2015 寻宝游戏

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

  5. [bzoj3991] [洛谷P3320] [SDOI2015] 寻宝游戏

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

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

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

  7. BZOJ3991 寻宝游戏 LCA 虚树 SET

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

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

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

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

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

随机推荐

  1. hdu-3572 Task Schedule---最大流判断满流+dinic算法

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3572 题目大意: 给N个任务,M台机器.每个任务有最早才能开始做的时间S,deadline E,和持 ...

  2. python_53_函数补充

    def test1(x,y=2): print(x,y) test1(1) test1(1,3) test1(1,y=4) #默认参数特点:调用函数的时候,默认参数非必须传递,默认参数放在后边 #用途 ...

  3. RxJava2 方法总结

    RxJava2 方法总结 看了许多讲解RxJava的文章,有些文章讲解的内容是基于第一个版本的,有些文章的讲解是通过比较常用的一些API和基础的概念进行讲解的. 但是每次看到RxJava的类中的几十个 ...

  4. Java源码——HashMap的源码分析及原理学习记录

    学习HashMap时,需要带着这几个问题去,会有很大的收获: 一.什么是哈希表 二.HashMap实现原理 三.为何HashMap的数组长度一定是2的次幂? 四.重写equals方法需同时重写hash ...

  5. JavaScript中的confirm的用法

    confirm()方法用于显示一个带有指定消息和ok以及取消按钮的对话框confirm(message,ok,cancel); message:表示在弹出框的对话框中现实的文本信息如果用户点击确定按钮 ...

  6. c语言中--typeof--关键字用法

    C语言中 typeof 关键字是用来定义变量数据类型的.在linux内核源代码中广泛使用. 下面是Linux内核源代码中一个关于typeof实例: #define min(x, y) ({ \ typ ...

  7. cf519C. A and B and Team Training(找规律)

    题意 $a$个学生,$b$个教练 可以两个学生和一个教练一组,也可以两个教练和一个学生一组,问最多组成多少组 Sol 发题解的目的是为了纪念一下自己的错误思路 刚开始想的是:贪心的选,让少的跟多的分在 ...

  8. 常用自写函数[更新ing]

    int gcd (int x, int y)//最大公约数 { return y == 0 ? x : gcd( y , x % y ); } int lcm(int x, int y)//最小公倍数 ...

  9. Redis之List类型操作

    接口: package com.net.test.redis.base.dao; import java.util.List; /** * @author *** * @Time:2017年8月10日 ...

  10. 一个batch的数据如何做反向传播

    一个batch的数据如何做反向传播 对于一个batch内部的数据,更新权重我们是这样做的: 假如我们有三个数据,第一个数据我们更新一次参数,不过这个更新只是在我们脑子里,实际的参数没有变化,然后使用原 ...