题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3991
题目分析:一开始看到这题完全没头绪,感觉应该很简单然而就是不会。过了一会儿我忽然间记起来,某个点在当前虚树上的父亲就等于它与DFS序中前驱后继的LCA深度最大的那个。然后就可以用一波分类讨论,看一下它是不是当前点集中某两个点的LCA,以及它是不是当前虚树的叶子节点/根节点之类的。
后来看了别人的做法,发现自己的方法真的十分djfklajsfidsakloivcxnmwiqjkjsaldjjwqweriovuxczouq。其实只需要用一个set按DFS序维护当前点集,答案便是相邻两个点的路径长度之和(首尾算相邻)。因为这样就相当于刚好DFS了一遍整棵虚树。然后考虑加点删点对答案的影响即可。时间 O(nlog(n)) O ( n log ( n ) ) 。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
const int maxn=100100;
const int maxl=20;
typedef long long LL;
struct edge
{
int obj,len;
edge *Next;
} e[maxn<<1];
edge *head[maxn];
int cur=-1;
int fa[maxn][maxl];
int dep[maxn];
LL dis[maxn];
int dfsx[maxn];
int dfn[maxn];
int Time=0;
set <int> Node;
int n,m;
LL ans=0;
void Add(int x,int y,int z)
{
cur++;
e[cur].obj=y;
e[cur].len=z;
e[cur].Next=head[x];
head[x]=e+cur;
}
void Dfs(int node)
{
dfn[node]=++Time;
dfsx[Time]=node;
for (edge *p=head[node]; p; p=p->Next)
{
int son=p->obj;
if (son==fa[node][0]) continue;
fa[son][0]=node;
dep[son]=dep[node]+1;
dis[son]=dis[node]+(long long)p->len;
Dfs(son);
}
}
int Prev(int x)
{
set <int> :: iterator p=Node.find(dfn[x]);
if (p==Node.begin()) p=Node.end();
p--;
return dfsx[*p];
}
int Succ(int x)
{
set <int> :: iterator p=Node.find(dfn[x]);
p++;
if (p==Node.end()) p=Node.begin();
return dfsx[*p];
}
int Lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int j=maxl-1; j>=0; j--)
if (dep[ fa[x][j] ]>=dep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=maxl-1; j>=0; j--)
if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
LL Dis(int x,int y)
{
int z=Lca(x,y);
return (dis[x]+dis[y]-2LL*dis[z]);
}
int main()
{
//freopen("3991.in","r",stdin);
//freopen("3991.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) head[i]=NULL;
for (int i=1; i<n; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);
Add(y,x,z);
}
dep[1]=1;
Dfs(1);
for (int j=1; j<maxl; j++)
for (int i=1; i<=n; i++)
fa[i][j]=fa[ fa[i][j-1] ][j-1];
Node.clear();
for (int i=1; i<=m; i++)
{
int x;
scanf("%d",&x);
if (Node.count(dfn[x]))
{
int p=Prev(x);
int s=Succ(x);
if (p!=x)
{
ans-=Dis(p,x);
if (p!=s) ans-=Dis(s,x),ans+=Dis(s,p);
else ans-=Dis(p,x);
}
Node.erase(dfn[x]);
}
else
{
Node.insert(dfn[x]);
int p=Prev(x);
int s=Succ(x);
if (p!=x)
{
ans+=Dis(p,x);
if (p!=s) ans+=Dis(s,x),ans-=Dis(s,p);
else ans+=Dis(p,x);
}
}
printf("%lld\n",ans);
}
return 0;
}