版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/82749276
题目链接:点击这里
解题思路:
首先预处理出原来树中节点u的C(u)值,那么在给出的ki个节点后,将他们根据原C()大小从大到小排序.
那么假设最小情况下最大值不会超过第i个C()值,那么意思就是前i个节点的C()值要做出改变才行,怎么让他们都改变呢?
将红点设在前i个点的最近公共祖先上,就可以将他们都改变,且尽量最小.
对于前i个点C()的变化后最大值也可以递推求出.
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
int t,n,m,R[mx],cnt[mx],fa[mx][20];
int deep[mx];
ll D[mx],dis[mx];
bool red[mx];
vector <pair<int,int>> vec[mx];
void dfs(int x,int f)
{
if(red[x]) R[x] = x;
else R[x] = R[f];
dis[x] = (D[x]-D[R[x]]);
for(auto v:vec[x])
{
if(v.fi==f) continue;
D[v.fi] = D[x] + v.se;
deep[v.fi] = deep[x] + 1;
fa[v.fi][0] = x;
dfs(v.fi,x);
}
}
bool cmp(ll a,ll b)
{
return dis[a] > dis[b];
}
void RMQ(int N){
for(int j=1;(1<<j)<=N;j++)
for(int i=1;i<=N;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v){
if(deep[u]<deep[v]) swap(u,v);
int de=log(deep[u])/log(2.0);
for(int i=de;i>=0;i--)
if(deep[u]-(1<<i)>=deep[v])
u=fa[u][i];
if(v==u) return u;
for(int i=de;i>=0;i--){
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
}
return fa[v][0];
}
int main()
{
int t,q;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&q);
int a,b,c;
for(int i=1;i<=n;i++) red[i] = 0,vec[i].clear();
for(int i=1;i<=m;i++){
scanf("%d",&a);
red[a] = 1;
}
dis[n+1] = D[1] = dis[1] = 0;
deep[1] = 1;
for(int i=1;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
vec[a].push_back(make_pair(b,c));
vec[b].push_back(make_pair(a,c));
}
dfs(1,0);
RMQ(n);
int k;
while(q--){
scanf("%d",&k);
ll ans = 0,maxx = 0,lon;
for(int i=0;i<k;i++){
scanf("%d",cnt+i);
}
cnt[k] = n+1;
sort(cnt,cnt+k,cmp);
ans = dis[cnt[0]];
int far = cnt[0],mom,Mdep = deep[R[cnt[0]]];
ans = min(ans,dis[cnt[1]]);
for(int i=1;i<k;i++)
{
mom = LCA(far,cnt[i]);
Mdep = max(Mdep,deep[R[cnt[i]]]);
if(deep[mom]<deep[far]) maxx += D[far] - D[mom];
if(Mdep>=deep[mom]) break;
maxx = max(D[cnt[i]]-D[mom],maxx);
far = mom;
ans = min(ans,max(maxx,dis[cnt[i+1]]));
}
printf("%lld\n",ans);
}
}
return 0;
}