http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4048
比赛时思路很普通 队友按二分写的 无限TLE 复杂度还是太高
借鉴了这篇博客 思路很妙https://blog.csdn.net/lee_w_j__/article/details/82748521
每个黑点的花费只和最近的红点祖先有关 并且一次查询中只取最大值 利用这个特点 对查询的点按花费降序排序 记为p1>p2>...>pk 若要使最终答案小于等于pi 那选择变红的点必须是[1,i]这些点的lca才行 因为如果不想办法把这些点的花费减小 答案肯定不会小于等于pi 所有扫一遍并不断求lca即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct node
{
ll w;
int v,next;
};
node edge[2*maxn];
ll dis[maxn];
int dp[maxn][20];
int first[maxn],book[maxn],deep[maxn],red[maxn],pre[maxn];
int n,m,q,num;
bool cmp(int u,int v)
{
return dis[u]-dis[red[u]]>dis[v]-dis[red[v]];
}
void addedge(int u,int v,ll w)
{
edge[num].v=v;
edge[num].w=w;
edge[num].next=first[u];
first[u]=num++;
}
void dfs(int cur,int fa,int anc)
{
ll w;
int i,v;
for(i=first[cur];i!=-1;i=edge[i].next){
v=edge[i].v,w=edge[i].w;
if(v!=fa){
dp[v][0]=cur;
deep[v]=deep[cur]+1,dis[v]=dis[cur]+w;
if(book[v]){
red[v]=v;
dfs(v,cur,v);
}
else{
red[v]=anc;
dfs(v,cur,anc);
}
}
}
}
void init()
{
int i,j;
dp[1][0]=0;
deep[1]=1,dis[1]=0;
red[1]=1;
dfs(1,0,1);
for(j=1;(1<<j)<=n;j++){
for(i=1;i<=n;i++){
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
}
int getlca(int u,int v)
{
int i;
if(deep[u]<deep[v]) swap(u,v);
for(i=log2(n);i>=0;i--){
if(deep[dp[u][i]]>=deep[v]) u=dp[u][i];
}
if(u==v) return u;
for(i=log2(n);i>=0;i--){
if(dp[u][i]!=dp[v][i]) u=dp[u][i],v=dp[v][i];
}
return dp[u][0];
}
int main()
{
ll w,ans,res1,res2,preval,val;
int t,i,j,k,u,v,prelca,lca;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&q);
memset(first,-1,sizeof(first));
memset(book,0,sizeof(book));
num=0;
for(i=1;i<=m;i++){
scanf("%d",&u);
book[u]=1;
}
for(i=1;i<=n-1;i++){
scanf("%d%d%lld",&u,&v,&w);
addedge(u,v,w),addedge(v,u,w);
}
init();
while(q--)
{
scanf("%d",&k);
for(i=1,j=0;i<=k;i++){
scanf("%d",&u);
if(!book[u]) pre[++j]=u;
}
k=j;
if(k<=1) printf("0\n");
else{
sort(pre+1,pre+k+1,cmp);
ans=dis[pre[2]]-dis[red[pre[2]]],preval=0;
prelca=pre[1];
for(i=1;i<=k;i++){
lca=getlca(prelca,pre[i]);
res1=preval+dis[prelca]-dis[lca];
res2=min(dis[pre[i]]-dis[red[pre[i]]],dis[pre[i]]-dis[lca]);
val=max(res1,res2);
if(i+1<=k) ans=min(ans,max(val,dis[pre[i+1]]-dis[red[pre[i+1]]]));
else ans=min(ans,val);
prelca=lca,preval=val;
}
printf("%lld\n", ans);
}
}
}
return 0;
}