题意:
给定一颗带权的树(n<=1e5),维护一个动态的集合(即插入点和删除点),求从其中一点出发到达所有点并返回的最小距离。
分析:
到达所有点并返回,是这些点用最少的边连起来的权值的2倍。这样只需动态计算,最少边的和。
这里以1为根节点,跑一遍dfs序。
考虑插入:那么如果插入点得dfs序,在集合中存在点dfs序的中间,找到比之小的最大点,和比之大的最小点,因为插入点在内部这两点连线与该点得距离最小。
否则,插入点在外部,找dfs序最大和最小点,即可。
删除是插入的逆操作。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <list>
#include <cstdlib>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <cassert>
#define ALL(a) a.begin(), a.end()
#define clr(a, x) memset(a, x, sizeof a)
#define X first
#define Y second
#define pb push_back
#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rep1(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<(int)n;i++)
using namespace std;
const double eps = 1e-10;
typedef long long LL;
typedef long long ll;
typedef pair<int, int> pii;
const int oo =0x3f3f3f3f;
const int maxn=100000+100;
const int DEG=30;
struct Edge
{
int v, nxt , cap;
} edge[maxn<<1];
int n, head[maxn], tot, fa[maxn][DEG], deg[maxn], sz[maxn];
void init()
{
clr(head, -1);
tot=0;
}
void AddEdge(int u, int v ,int c)
{
edge[tot].v=v;
edge[tot].cap=c;
edge[tot].nxt=head[u];
head[u]=tot++;
}
void dfs(int u)
{
for(int i=1; i<DEG; i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
sz[u]=1;
for(int i=head[u]; ~i; i=edge[i].nxt)
{
int v=edge[i].v;
if(v==fa[u][0])continue ;
deg[v]=deg[u]+1;
fa[v][0]=u;
dfs(v);
sz[u]+=sz[v];
}
}
int par(int u, int det)
{
for(int i=0; det; det>>=1, i++)
if(det&1)
u=fa[u][i];
return u;
}
int LCA(int u, int v)
{
if(deg[u]>deg[v])swap(u, v);
int tu=u, tv=v;
tv=par(v, deg[v]-deg[u]);
if(tu==tv)return tu;
for(int i=DEG-1; i>=0; i--)
{
if(fa[tu][i]==fa[tv][i])continue ;
tu=fa[tu][i], tv=fa[tv][i];
}
return fa[tu][0];
}
int id[maxn] , cnt_=0 ;
ll d[maxn];
void init_dfs(int u,int f , ll len)
{
id[u] = ++cnt_;
d[u] = len;
for(int i=head[u]; ~i; i=edge[i].nxt)
{
int v=edge[i].v;
if(v==f)continue ;
init_dfs(v,u,len+edge[i].cap);
}
}
struct node
{
int id,u;
node(int u=0,int id=0):u(u),id(id) {}
bool operator<(const node& rhs)const
{
return id < rhs.id;
}
};
set<node> que;
typedef set<node>::iterator set_p;
ll now = 0;
void cal(int u)
{
if(que.empty()) {
que.insert(node(u,id[u])); return ;
}
set_p p = que.find(node(u,id[u])) , p1, p2;
int flag = -1;
if(p == que.end())
{
que.insert(node(u,id[u]));
flag = 1;
}
p = que.find(node(u,id[u]));
p1 = p2 = p; set_p ed = que.end(); --ed;
if(p == que.begin()) p1++,p2=ed;
else if(p == ed) p1=que.begin(),p2=ed,--p2;
else p1--, p2++;
int y = p2->u;
int x = p1->u;
now+=((ll)d[u]-d[LCA(x,u)]-d[LCA(y,u)]+d[LCA(x,y)])*flag;
if(flag == -1) que.erase(p);
}
int Q;
int main()
{
scanf("%d %d", &n ,&Q);
init();
for(int i=0; i<n-1; i++)
{
int u, v , c;
scanf("%d%d%d", &u, &v,&c);
AddEdge(u, v , c);
AddEdge(v, u , c);
}
deg[1]=0;
fa[1][0]=1;
dfs(1);
cnt_ = 0; d[1] = 0;
init_dfs(1,-1,0);
que.clear();
now = 0;
while(Q--)
{
int u;
scanf("%d",&u);
cal(u);
printf("%lld\n",now*2);
}
}