题目链接

  其实这题用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. go语言,爬取百度贴吧指定贴所有内容

    初级爬虫,为了学习一下常用的goquery. goquery 配置 go get https://github.com/PuerkitoBio/goquery 会提示不支持https方式 解决方案: ...

  2. python剑指offer 顺时针打印指针

    题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数 ...

  3. 说说qwerty、dvorak、colemak三种键盘布局

    [qwerty布局] qwerty布局大家应该都很熟悉了,全世界最普及的键盘布局. 截止到去年接触并使用dvorak布局之前,我使用了十几年qwerty布局,在http://speedtest.10f ...

  4. 使用 Repeater方式和完全静态页面使用AJAX读取和提交数据

    1.使用Repeater方式: Comments.aspx <html xmlns="http://www.w3.org/1999/xhtml"> <head r ...

  5. 一次线上CPU高的问题排查实践

    一次线上CPU高的问题排查实践 前言 近期某一天上班一开电脑,就收到了运维警报,有两台服务CPU负载很高,同时收到一线同事反馈 系统访问速度非常慢,几乎无响应. 一个美好的早晨,最怕什么就来什么.只好 ...

  6. mysql 5.7 编译安装脚本。

    此脚本尽量运行在centos 服务器上面,用于编译安装mysql 5.7 将此脚本和相应的软件 都放到/usr/local/src 目录下面 由于不能上传附件  所以需要把cmake-3.9.6.ta ...

  7. 微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js)

    微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js) 微信小游戏 demo 飞机大战 代码分析(一)(main.js) 微信小游戏 demo 飞 ...

  8. JZOJ 5196. 【NOIP2017提高组模拟7.3】B

    5196. [NOIP2017提高组模拟7.3]B Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits   Goto Pro ...

  9. Hive如何根据表中某个字段动态分区

    使用hive储存数据时,需要对做分区,如果从kafka接收数据,将每天的数据保存一个分区(按天分区),保存分区时需要根据某个字段做动态分区,而不是傻傻的将数据写到某一个临时目录最后倒入到某一个分区,这 ...

  10. python3 练习题100例 (十五)

    这个比较难,主要难在考虑的问题太多,有好几个还没写出来.有空再来改进.请高手指教! #!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ ...