给定一颗带权的树(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); } }