传送门
SPFA超时妥妥的!
N-1条边,树上找最短路,八成是LCA
用经过的点两两建立要查询的LCA,边权设为1.
就可以转化为小机房的树那个题目233
#include <cstdio>
#include <iostream>
using namespace std;
const int maxm=501000;
struct node{
int net;
int to;
int cost;
int lca;
int ans;
};
bool vis[maxm];
int fat[maxm];
node edge[2][2*maxm];
int cnt[2],head[2][maxm];
int dis[maxm];
int t;
void add(int id,int x,int y,int c)
{
edge[id][++cnt[id]].to=y;
edge[id][cnt[id]].cost=c;
edge[id][cnt[id]].net=head[id][x];
head[id][x]=cnt[id];
}
int find(int x)
{
if(fat[x]==x) return x;
else return fat[x]=find(fat[x]);
}
void dfs(int x,int f,int sum)
{
dis[x]+=dis[f]+sum;
vis[x]=1;
fat[x]=x;
for(int K=head[0][x];K;K=edge[0][K].net)
{
int p=edge[0][K].to;
if(vis[p]) continue;
dfs(p,x,edge[0][K].cost);
fat[p]=x;
}
for(int i=head[1][x];i;i=edge[1][i].net)
{
int p=edge[1][i].to;
if(!vis[p]||edge[1][i].lca) continue;
edge[1][i].lca=find(p);
int ans=dis[x]+dis[p]-2*dis[edge[1][i].lca];
//printf("%d %d %d %d\n",x,p,edge[1][i].lca,ans);
edge[1][i].ans=ans;
t+=ans;
if(i%2)
edge[1][i+1].lca=edge[1][i].lca,edge[1][i+1].ans=ans;
else
edge[1][i-1].lca=edge[1][i].lca,edge[1][i-1].ans=ans;
}
}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(0,x,y,1);
add(0,y,x,1);
}
scanf("%d",&m);
int last=1;
//scanf("%d",&last);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
add(1,last,x,0),add(1,x,last,0);
last=x;
}
dfs(1,0,0);
printf("%d",t);
}