题目:BZOJ3991.
题目大意:给定一棵
n
n
n个点的树,现在要求维护一个点集,支持:
1.加入一个树上的点.
2.删除一个树上的点.
3.不规定顺序,询问经过点集中每一个点并回到起点的最短路径.
若操作次数为
m
m
m,则
1
≤
n
,
m
≤
1
0
5
1\leq n,m\leq 10^5
1≤n,m≤105.
显然地,最短路径肯定是从虚树的根开始依次dfs每一个点最后返回经过的总路程,也就是在原树上按照dfs序走最优.
问题变成动态维护虚树.考虑每次加一个点 x x x时,显然是插入到在dfs序意义下 x x x的前驱与后继之间,可以用一个set来维护这个东西.
再来考虑如何维护答案,每插入一个点 x x x,设 x x x的前驱为 l l l后继为 r r r,那么答案会减去 d i s ( l , r ) dis(l,r) dis(l,r)并加上 d i s ( x , l ) dis(x,l) dis(x,l)和 d i s ( x , r ) dis(x,r) dis(x,r).
同理,删除的时候就答案会减去 d i s ( x , l ) dis(x,l) dis(x,l)和 d i s ( x , r ) dis(x,r) dis(x,r)并加上 d i s ( l , r ) dis(l,r) dis(l,r).
然后就可以 O ( ( n + m ) log n ) O((n+m)\log n) O((n+m)logn)解决这个问题了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
#define setit set<int>::iterator
const int N=100000;
int n,m;
struct side{
int y,next,v;
}e[N*2+9];
int lin[N+9],cs;
void Ins(int x,int y,int v){e[++cs].y=y;e[cs].v=v;e[cs].next=lin[x];lin[x]=cs;}
struct node{
int fa,dep,siz,son,top,dfs;
LL dis;
}d[N+9];
int ord[N+9],co;
void Dfs_ord1(int k,int fa){
d[k].fa=fa;
d[k].dep=d[fa].dep+1;
d[k].siz=1;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa){
d[e[i].y].dis=d[k].dis+e[i].v;
Dfs_ord1(e[i].y,k);
d[k].siz+=d[e[i].y].siz;
if (d[e[i].y].siz>d[d[k].son].siz) d[k].son=e[i].y;
}
}
void Dfs_ord2(int k,int top){
d[k].top=top;
d[k].dfs=++co;
ord[co]=k;
if (d[k].son) Dfs_ord2(d[k].son,top);
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_ord2(e[i].y,e[i].y);
}
int Query_lca(int x,int y){
for (;d[x].top^d[y].top;x=d[d[x].top].fa)
if (d[d[x].top].dep<d[d[y].top].dep) swap(x,y);
return d[x].dep<d[y].dep?x:y;
}
LL Query_dis(int x,int y){return d[x].dis+d[y].dis-2*d[Query_lca(x,y)].dis;}
set<int>s;
LL ans;
void Insert(int k){
s.insert(d[k].dfs);
setit lit=s.find(d[k].dfs),rit=lit;--lit;++rit;
if (lit==s.end()) --lit;
if (rit==s.end()) rit=s.begin();
ans-=Query_dis(ord[*lit],ord[*rit]);
ans+=Query_dis(ord[*lit],k);
ans+=Query_dis(ord[*rit],k);
}
void Erase(int k){
setit lit=s.find(d[k].dfs),rit=lit;--lit;++rit;
if (lit==s.end()) --lit;
if (rit==s.end()) rit=s.begin();
ans-=Query_dis(ord[*lit],k);
ans-=Query_dis(ord[*rit],k);
ans+=Query_dis(ord[*lit],ord[*rit]);
s.erase(d[k].dfs);
}
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i){
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
Ins(x,y,v);Ins(y,x,v);
}
}
Abigail work(){
Dfs_ord1(1,0);
Dfs_ord2(1,1);
}
Abigail getans(){
for (int i=1;i<=m;++i){
int x;
scanf("%d",&x);
s.find(d[x].dfs)==s.end()?Insert(x):Erase(x);
printf("%lld\n",ans);
}
}
int main(){
into();
work();
getans();
return 0;
}