传送门
题解:
虚树好题,后续的处理其实也可以用倍增,不过树剖常数那么小直接上树剖+ST表完全没有压力。
首先看到题目这个形式大概就是要用虚树的了。
求的是距离所有关键点的最小值的最大值。
答案点有三种情况,在虚树节点上,在虚树缩掉的边的子树中,在虚树上的点的无关键点子树中。
第一种树形DP,第二种树剖+DFS序+ST表,第三种BFS序+ST表。
非常好写
写完了才发现第三种其实也可以用DFS序
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+7;
int n,m;
int el[N],nxt[N<<1|1],to[N<<1|1],ec;
inline void adde(int u,int v){
nxt[++ec]=el[u],el[u]=ec,to[ec]=v;
nxt[++ec]=el[v],el[v]=ec,to[ec]=u;
}
int Log[N];
class ST{
private:
int st[20][N];
public:
void init(int n){
for(int re i=1;i<=Log[n];++i)
for(int re j=1;j+(1<<i)-1<=n;++j)
st[i][j]=std::max(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
void set(int p,int v){st[0][p]=v;}
int operator[](int o)cs{return st[0][o];}
int operator()(int l,int r)cs{int t=Log[r-l+1];
return std::max(st[t][l],st[t][r-(1<<t)+1]);
}
}up,dn,sub;
int fa[N],son[N],siz[N];
int d[N],top[N];
int dfn[N],nd[N],dfc;
int bfn[N],L[N],R[N],bfc;
int f[N],g[N],s[N];
void dfs1(int u,int p){
fa[u]=p,d[u]=d[p]+1;siz[u]=1;
for(int re e=el[u],v;e;e=nxt[e])
if((v=to[e])!=p){
dfs1(v,u);siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
if(1+f[v]>f[u])g[u]=f[u],f[u]=1+f[v];
else if(1+f[v]>g[u])g[u]=1+f[v];
}
}
void dfs2(int u,int tp){
top[u]=tp,dfn[u]=++dfc,nd[dfc]=u;
for(int re e=el[u],v;e;e=nxt[e])
if((v=to[e])!=fa[u])s[v]=1+std::max(s[u],1+f[v]==f[u]?g[u]:f[u]);
if(son[u])dfs2(son[u],tp);
for(int re e=el[u],v;e;e=nxt[e])
if((v=to[e])!=fa[u]&&v!=son[u])dfs2(v,v);
int mx=1+f[son[u]]==f[u]?g[u]:f[u];
up.set(dfn[u],mx-d[u]);
dn.set(dfn[u],mx+d[u]);
}
std::queue<int> q;
void bfs(){
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();bfn[u]=++bfc;
sub.set(bfn[u],1+f[u]);
if(fa[u]){
R[fa[u]]=bfn[u];
if(!L[fa[u]])L[fa[u]]=bfn[u];
}
for(int re e=el[u],v;e;e=nxt[e])
if((v=to[e])!=fa[u])q.push(v);
}
}
int LCA(int u,int v){
while(top[u]!=top[v])d[top[u]]<d[top[v]]?v=fa[top[v]]:u=fa[top[u]];
return d[u]<d[v]?u:v;
}
int jump(int u,int k){
while(k>d[u]-d[top[u]]){
k-=d[u]-d[top[u]]+1;
u=fa[top[u]];
}return nd[dfn[u]-k];
}
int find_to(int u,int p){int res=0;
while(top[u]!=top[p]){
res=top[u];
u=fa[top[u]];
}return u==p?res:son[p];
}
int qy(int u,int v,ST &T,int coe){
int ans=-1e9;
while(d[u]>d[v]){
int p=fa[u];
if(u==son[p])ans=std::max(ans,T(std::max(dfn[top[p]],dfn[v]),dfn[p]));
else {
ans=std::max(ans,coe*d[p]+(1+f[u]==f[p]?g[p]:f[p]));
if(p!=top[p])ans=std::max(ans,T(std::max(dfn[top[p]],dfn[v]),dfn[fa[p]]));
}u=top[p];
}
return ans;
}
namespace VT{
int el[N],nxt[N],key[N];
int dis[N],from[N];
int vt[N],k,rt,ans;
int st[N],tp;
inline void adde(int u,int v){if(u==v)return ;nxt[v]=el[u],el[u]=v;}
void dp1(int u){
if(key[u])dis[u]=0,from[u]=u;
else dis[u]=1e9,from[u]=0;
for(int re v=el[u];v;v=nxt[v]){
dp1(v);if(d[v]-d[u]+dis[v]<dis[u]){
dis[u]=dis[v]-d[u]+d[v];
from[u]=from[v];
}
}
}
void dp2(int u){
for(int re v=el[u];v;v=nxt[v]){
if(d[v]-d[u]+dis[u]<dis[v]){
dis[v]=dis[u]+d[v]-d[u];
from[v]=from[u];
}dp2(v);
}
}
void sol(int u){
tp=0;
for(int re v=el[u];v;v=nxt[v]){
int c=find_to(v,u);st[++tp]=bfn[c];
if(from[u]!=from[v]){
int dd=(dis[u]+dis[v]+d[v]-d[u])/2-dis[v];
int t=jump(v,(dd==d[v]-d[u])?dd-1:dd);
ans=std::max(ans,dis[v]+d[v]+qy(v,t,up,-1));
ans=std::max(ans,dis[u]-d[u]+qy(t,c,dn,1));
}else {
if(dis[u]<dis[v])ans=std::max(ans,dis[u]-d[u]+qy(v,c,dn,1));
else ans=std::max(ans,dis[v]+d[v]+qy(v,c,up,-1));
}
}
if(R[u]){
std::sort(st+1,st+tp+1);
int res=0,lst=L[u];
for(int re i=1;i<=tp;++i){
if(st[i]>lst)res=std::max(res,sub(lst,st[i]-1));
lst=st[i]+1;
}if(R[u]>=lst)res=std::max(res,sub(lst,R[u]));
ans=std::max(ans,res+dis[u]);
}
for(int re v=el[u];v;v=nxt[v])sol(v);
}
void work(){
ec=0;k=gi();for(int re i=1;i<=k;++i)vt[i]=gi();
std::sort(vt+1,vt+k+1,[](int u,int v){return dfn[u]<dfn[v];});
for(int re i=2;i<=k;++i){
int p=LCA(vt[i-1],vt[i]);
el[p]=0,key[p]=false;
}
for(int re i=1;i<=k;++i)el[vt[i]]=0,key[vt[i]]=true;
rt=st[tp=1]=LCA(vt[1],vt[k]);
for(int re i=1;i<=k;++i){
int p=LCA(vt[i],st[tp]);
while(tp>1&&d[st[tp-1]]>=d[p])
adde(st[tp-1],st[tp]),--tp;
if(d[st[tp]]>=d[p])adde(p,st[tp]),st[tp]=p;
st[++tp]=vt[i];
}
while(tp>1)adde(st[tp-1],st[tp]),--tp;
dp1(rt);dp2(rt);ans=dis[rt]+s[rt];
sol(rt);cout<<ans<<"\n";
}
}
signed main(){
#ifdef zxyoi
freopen("nothing_to_do.in","r",stdin);
#endif
n=gi();m=gi();
for(int re i=1;i<n;++i)adde(gi(),gi());
for(int re i=2;i<=n;++i)Log[i]=Log[i>>1]+1;
dfs1(1,0);dfs2(1,1);bfs();
up.init(n),dn.init(n),sub.init(n);
memset(el,0,sizeof el);while(m--)VT::work();
return 0;
}