先考虑 $m=n-1$ 的部分如何处理。
$f_i$ 表示 Alice 可以用 $1$ 步占据 $i$ 号点,在 $i$ 号点子树内进行游戏的答案。
我们用 $g_i$ 表示 $i$ 号点子树内距离 $i$ 号点最近的被 Bob 占据的距离
那么如果 $i \in T$,显然 $f_i=g_i$
否则 $f_i=\min(g_i,\sum_{j \in son_i} \max(f_j-\operatorname{dis(i,j)},0))$
如果环上存在 Bob 占据的节点,显然该节点在环上往 $2$ 侧的拓展是独立的,我们将其分裂成 $2$ 个虚点,分别连接相邻的 $2$ 侧节点即可。
考虑更一般的情况,假设 $1$ 号节点在环上,我们分如下几种情况考虑。
- 将环提为根,分裂成基环大小棵树,不存在跨树覆盖的情况,那么此时我们只要算出每棵树的答案,保证顺逆时针答案的前缀和均 $\geq 0$ (即不管Alice从哪个方向覆盖都能即时转移),只要顺逆时针分别进行一次贪心,当前缀和 $<0$ 时强行修正,易证这个贪心时正确的。
- 存在跨树覆盖的情况,那么此时我们会发现,如果有超过 $2$ 棵树进行跨树覆盖,显然是不合法的,如果存在一棵树跨树覆盖,我们可以枚举其覆盖到环上的左右端点,那么此时因为该节点在环上,整个环被割裂成 $2$ 部分,分别求 $2$ 侧答案进行求和即可,注意此时 Bob 从子树内出来的步骤是公共的,需要特判一下,如果有 $2$ 棵树进行跨树覆盖,我们枚举这 $2$ 个节点,并枚举其覆盖到的左右端点,分别算答案相加即可。
如果 $1$ 号点不在环上,我们可以将整个环部分的答案先处理出来,当作一个虚点挂在 $1$ 号点所在的子树上,注意此时可能会有环上节点覆盖到 $1$ 号点子树内的情况,再挂一个虚点,修改其$g_i$ 即可。
//zxggtxdy!!!
#include<bits/stdc++.h>
using namespace std;
const int N=1007; bool tag,f1[N],f2[N],fl[N],gt[N];
int n,m,s,t,op,rt,og,st[N],pt[N],f[N],G[N],fa[N],ft[N],Gt[N],dis[N][N]; long long res,V,Gs,F[N],D[N],va[N],vb[N],vc[N],vd[N],ch[N][2]; vector<int>v[N],w[N],vt[N];
struct edg{
int a,b,c;
}e[N];
inline int find(int u){
if(f[u]==u) return u; return f[u]=find(f[u]);
}
inline void chk(int u){
if(u==1) tag=1;
for(int i=0;i<v[u].size();i++){
int x=v[u][i]; if(fa[u]==x) continue; fa[x]=u,chk(x);
}
}
inline void dfs(int u,int dep){
F[u]=0; if(u==rt) F[u]=V,D[u]=Gs;
for(int i=0;i<v[u].size();i++){
int x=v[u][i]; if(fa[u]==x) continue;
ft[x]=w[u][i],fa[x]=u,dfs(x,dep+w[u][i]+1);
if(D[x]!=-1){
D[x]+=w[u][i]+1; if(D[u]==-1) D[u]=D[x]; else D[u]=min(D[u],D[x]);
}
F[u]+=max(0ll,F[x]-1-w[u][i]);
}
if(f1[u]) D[u]=0,F[u]=0;
else{
if(f2[u]){
if(D[u]!=-1) F[u]=D[u]+1; else F[u]=1e15;
}
else if(u!=1){
if(D[u]!=-1&&F[u]>=D[u]+1) F[u]=D[u]+1;
}
}
if(u==1&&!f2[1]){
res=min(res,F[1]);
}
}
inline void bfs(int x,int y,int fa){
st[++st[0]]=x;
if(x==y){
for(int i=1;i<=st[0];i++) fl[st[i]]=1,Gt[i]=st[i];
}
for(int i=0;i<v[x].size();i++){
int c=v[x][i]; if(fa==c) continue; bfs(c,y,x);
}
st[0]--;
}
int main(){
int C,a,b,c; cin>>C;
while(C--){
rt=0;
scanf("%d%d%d%d",&n,&m,&s,&t); op++; bool tg=0;
for(int i=1;i<=n;i++) f[i]=i,fl[i]=0; int x,y;
for(int i=1;i<=n;i++) v[i].resize(0),w[i].resize(0),f1[i]=0,f2[i]=0,D[i]=-1;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
e[i].a=a,e[i].b=b,e[i].c=c;
if(find(a)==find(b)){
x=a,y=b; continue;
}
v[a].push_back(b),v[b].push_back(a);
w[a].push_back(c),w[b].push_back(c);
f[find(a)]=find(b);
}
for(int i=1;i<=s;i++){
scanf("%d",&a),f1[a]=1;
}
for(int i=1;i<=t;i++){
scanf("%d",&a),f2[a]=1;
}
if(f2[1]){
puts("1000000"); continue;
}
if(n==m){
st[0]=0,bfs(x,y,0);
for(int i=1;i<=n*2;i++) v[i].resize(0),w[i].resize(0);
for(int i=n+1;i<=n*2;i++) f1[i]=f2[i]=0;
for(int i=1;i<=n;i++) if(f1[i]&&fl[i]) x=i,tg=1;
for(int i=1;i<=n;i++) if(fl[i]) st[++st[0]]=i;
for(int i=1;i<=m;i++){
a=e[i].a,b=e[i].b,c=e[i].c;
if(tg){
if(a==x) a=++n,f1[a]=1;
else if(b==x) b=++n,f1[b]=1;
}
v[a].push_back(b),v[b].push_back(a);
w[a].push_back(c),w[b].push_back(c);
}
}
for(int i=1;i<=n;i++) if(f1[i]) f2[i]=0;
res=1000000;
if(m==n-1||tg){
dfs(1,0);
printf("%lld\n",res);
}
else{
res=1000000,V=1e15; Gs=1e15;
for(int i=1;i<=n;i++) gt[i]=0,fa[i]=0,F[i]=0;
for(int i=1;i<=st[0];i++) gt[st[i]]=1,st[i]=Gt[i];
for(int i=1;i<=n;i++) v[i].resize(0),w[i].resize(0);
for(int i=1;i<=m;i++){
a=e[i].a,b=e[i].b,c=e[i].c,dis[a][b]=dis[b][a]=c+1;
if(gt[a]&>[b]){
continue;
}
v[a].push_back(b),v[b].push_back(a);
w[a].push_back(c),w[b].push_back(c);
}
for(int i=1;i<=st[0];i++){
tag=0,chk(st[i]);
if(!tag) continue; int L=0;
for(int j=i;j<=st[0];j++) pt[++L]=st[j];
for(int j=1;j<i;j++) pt[++L]=st[j];
for(int j=1;j<=L;j++) st[j]=pt[j]; break;
}
st[st[0]+1]=st[1];
for(int i=2;i<=st[0];i++){
dfs(st[i],0),ch[i][0]=ch[i][1]=1e15,og=0;
if(D[st[i]]==-1) continue; long long Q=1,E=1;
for(int j=1;j<i;j++) Q+=dis[st[j]][st[j+1]];
for(int j=i;j<=st[0];j++) E+=dis[st[j]][st[j+1]];
if(st[1]!=1) V=min(V,min(Q,E)+D[st[i]]);//block up the circle
if(st[1]!=1) Gs=min(Gs,min(Q,E)+D[st[i]]);
}
Gs--;
va[1]=0,vb[1]=0;
for(int i=2;i<=st[0];i++){
va[i]=va[i-1],vb[i]=vb[i-1]+dis[st[i-1]][st[i]]-f2[st[i]]; long long D=F[st[i]];
if(D-vb[i]>0) va[i]+=D-vb[i],vb[i]=0; else vb[i]-=D; vb[i]+=f2[st[i]];
}
vc[st[0]+1]=vd[st[0]+1]=0;
for(int i=st[0];i>=2;i--){
vc[i]=vc[i+1],vd[i]=vd[i+1]+dis[st[i]][st[i+1]]-f2[st[i]]; long long D=F[st[i]];
if(D-vd[i]>0) vc[i]+=D-vd[i],vd[i]=0; else vd[i]-=D; vd[i]+=f2[st[i]];
}
for(int i=2;i<=st[0];i++){
if(D[st[i]]==-1) continue;
long long A=0,B=0,T1=0,T2=0;
for(int j=1;j<=i-1;j++) T1+=dis[st[j]][st[j+1]];
for(int j=i+1;j<=st[0]+1;j++) T2+=dis[st[j-1]][st[j]];
A=0,B=0;
for(int j=i-1;j>=1;j--){
B=0;
for(int k=i+1;k<=st[0]+1;k++){
long long C=va[j]+vc[k];
long long X=vb[j]+dis[st[j]][st[j+1]]-1;
long long Y=vd[k]+dis[st[k]][st[k-1]]-1;
if(A-X<=-D[st[i]]&&B-Y<=-D[st[i]]){
//do nothing
}
else{
C+=D[st[i]]+min(max(A-X,B-Y),0ll);
C+=max(0ll,A-X)+max(0ll,B-Y);
}
ch[i][0]=min(max(0ll,A-X+D[st[i]])+va[j],ch[i][0]);
ch[i][1]=min(max(0ll,B-Y+D[st[i]])+vc[k],ch[i][1]);
V=min(V,C);
B+=dis[st[k-1]][st[k]];
}
A+=dis[st[j+1]][st[j]];
}
}
//choose two root
for(int i=2;i<=st[0];i++)
for(int j=i+1;j<=st[0];j++){
V=min(V,ch[i][0]+ch[j][1]);
}
//no Bob's operatr from other tree
long long S=0,ans=0;
for(int i=2;i<=st[0];i++){
S+=dis[st[i-1]][st[i]]-f2[st[i]];
if(F[st[i]]>=S) ans+=F[st[i]]-S,F[st[i]]=S,S=0;
else S-=F[st[i]]; S+=f2[st[i]];
}
S=0;
for(int i=st[0];i>=1;i--){
S+=dis[st[i+1]][st[i]]-f2[st[i]];
if(F[st[i]]>=S) ans+=F[st[i]]-S,F[st[i]]=S,S=0;
else S-=F[st[i]]; S+=f2[st[i]];
}
V=min(V,ans);
if(st[1]==1){
fa[1]=0,dfs(1,0);
printf("%lld\n",min(1000000ll,V+F[1]));
}
else{
fa[1]=0,rt=st[1],dfs(1,0),rt=0,printf("%lld\n",res);
}
}
}
}