Code:
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) // , freopen(s".out","w",stdout)
#define maxn 1000001
#define inf 1000000000
#define ll long long
using namespace std;
vector<int>G[maxn];
int edges,tim,root,top;
int hd[maxn], to[maxn<<1], val[maxn<<1], nex[maxn<<1];
int dep[maxn],Top[maxn],hson[maxn],siz[maxn],dfn[maxn],fa[maxn],arr[maxn],S[maxn],mk[maxn];
inline void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=1;
}
void dfs1(int u,int ff)
{
fa[u]=ff,siz[u]=1,dep[u]=dep[ff]+1,dfn[u]=++tim;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[hson[u]]) hson[u]=v;
}
}
void dfs2(int u,int tp)
{
Top[u]=tp;
if(hson[u]) dfs2(hson[u],tp);
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==fa[u]||v==hson[u]) continue;
dfs2(v,v);
}
}
inline int LCA(int x,int y)
{
while(Top[x]!=Top[y])
{
dep[Top[x]] > dep[Top[y]] ? x = fa[Top[x]] : y = fa[Top[y]];
}
return dep[x] < dep[y] ? x : y;
}
inline int getdis(int x,int y)
{
return dep[x] + dep[y] - (dep[LCA(x,y)] << 1);
}
inline void addvir(int u,int v)
{
G[u].push_back(v);
}
void insert(int x)
{
if(top<=1) { S[++top]=x; return; }
int lca=LCA(x, S[top]);
if(lca == S[top]) { S[++top] = x; return; }
while(top > 1 && dep[S[top - 1]] >= dep[lca]) addvir(S[top - 1], S[top]), --top;
if(lca != S[top]) addvir(lca, S[top]), S[top] = lca;
S[++top] = x;
}
bool cmp(int i,int j)
{
return dfn[i] < dfn[j];
}
ll ans=0,a1,a2;
int size[maxn],d1[maxn],d2[maxn],dmin[maxn],k;
void DP(int x)
{
size[x]=mk[x];
d1[x]=d2[x]=0, dmin[x]=inf;
for(int i=0;i<G[x].size();++i)
{
int v = G[x][i],w = getdis(x, G[x][i]);
DP(v);
if(mk[v]) dmin[x]=min(dmin[x],w);
else dmin[x]=min(dmin[x], w+dmin[v]);
int curd=w+d1[v];
if(curd > d1[x]) d2[x]=d1[x], d1[x]=curd;
else if(curd > d2[x]) d2[x] = curd;
ans+=1ll*size[v]*w*(k-size[v]),size[x]+=size[v];
}
a1=max(a1, 1ll*(d1[x] + d2[x]));
if(mk[x]) a2=min(a2, 1ll*dmin[x]);
G[x].clear();
}
inline void work()
{
scanf("%d",&k);
for(int i=1;i<=k;++i) scanf("%d",&arr[i]), mk[arr[i]] = 1;
sort(arr+1,arr+1+k,cmp);
S[top=0]=root=ans=0;
for(int i=1;i<=k;++i) insert(arr[i]);
for(int i=1;i<=top;++i) if(dep[S[i]] < dep[root] || !root) root = S[i];
while(top > 1) addvir(S[top-1], S[top]),--top;
a1=-inf, a2=inf, DP(root);
printf("%lld %lld %lld\n",ans,a2,a1);
for(int i=1;i<=top;++i) mk[arr[i]]=0;
}
int main()
{
// setIO("input");
int n;
scanf("%d",&n);
for(int i=1;i<n;++i)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b), add(b,a);
}
dep[1]=1,dfs1(1,0),dfs2(1,1);
int Q;
scanf("%d",&Q);
while(Q--) work();
return 0;
}
本文深入探讨了图论算法中的关键概念和技术,包括深度优先搜索、最近公共祖先(LCA)算法、离线查询处理以及动态规划在树上的应用。通过详细的代码实现和案例分析,为读者提供了全面的理解和实践指南。
643

被折叠的 条评论
为什么被折叠?



