题目链接

  其实这题用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. 二叉搜索树(BST)学习笔记

    简介 二叉搜索树(\(Binary\ Search\ Tree\)),简称\(BST\),用于在一个集合中查找元素. 性质 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右子树不为 ...

  2. dn.net/blueheart20/article/details/22080489

    dn.net/blueheart20/article/details/22080489

  3. leetcode - 二叉树最大深度

    二叉树最大深度 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示例: 给定二叉树 [3,9,20,null,nul ...

  4. SQL数据库查询出一张表中重复的数据,按某个字段来查找。

    例如表名为Course 需要查询出name重复的有那些??? 解答如下: 补充: 如:查询每个姓名出现大于2次,SQL如下 SELECT COUNT(NAME) as '出现次数',  NAME FR ...

  5. SQL初次接触

    1.SQL对大小写不敏感 2.部分SQL数据库要求结尾分号 3.分为两种DML(数据操作语言)和DDL(数据定义语言) sql中一些注意要点 1.设置主键 一般会在一个数据内设置一个主键(名字通常为i ...

  6. gitLab 服务器搭建 (自己服务器上搭建gitLab)

    环境 lunix(ubuntu) 1:添加文件 在   /etc/apt/sources.list.d/gitlab-ce.list 中添加一行 deb https://mirrors.tuna.ts ...

  7. 搭建Nginx反向代理做内网域名转发

    由于公司内网有多台服务器的 http 服务要映射到公司外网静态 IP,如果用路由的端口映射来做,就只能一台内网服务器的 80 端口映射到外网 80 端口,其他服务器的 80 端口只能映射到外网的非 8 ...

  8. 02.VUE学习二之数据绑定

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  9. python代码notepad++不变色问题。

    原来是文档后缀名是.txt造成的,应该改成.py,疏忽了...

  10. request_resource

    1.全局变量 resource结构体定义如下,指针parent.sibling.child用于构建树状结构. struct resource { resource_size_t start; reso ...