題目連接:https://loj.ac/problem/6184
每次詢問給一些關鍵點,詢問樹上每一個點離最近的關鍵點的距離(之後稱爲f(u))最大值是多少。
詢問數比較大,但 \sum{K} 和n是一個級別的,咱們考慮每次把詢問的點建成虛樹,在虛樹上統計答案。那些不在虛樹上的點的必定是經過虛樹上的點走到的,它們的f(u)也都是經過虛樹上的信息來維護的。c++
一、一個虛樹上的節點的其餘不在虛樹中的子樹中的答案,因爲要排除掉在虛樹上(或虛樹邊上)的兒子,須要預處理的時候對每一個點開個有序的vector記錄每一個兒子子樹最深值,查詢時找到第一個不在虛樹(邊)上的兒子就break,這樣統計這部分答案的均攤代價是O(虛樹度數)的。
二、一條虛樹上壓縮後的長度大於1的邊上的點的不在虛樹中的子樹中的答案。這部分咱們須要經過預處理的倍增數組O(log(n))地來找到從上面的節點u走最優或從下面的節點v走最優的分界點k。而後d---k詢問從d走到d->k中的一個點再往不包含d的子樹中走的最大值,k->u詢問u向下走不通過k的子樹最大值。這兩個東西均可以預先用倍增數組求出來,單次查詢O(log2(n))。數組
一、最好強制讓1是虛樹的根,不然最後還得考慮虛樹的根往上走再折回來的答案。
二、別忘了答案仍可能出在虛樹上,要把虛樹上節點的f值取個max。
接下來是一份AC代碼:spa
#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(register int i=(a);i<=(b);++i) typedef long long ll; const int N = 200005; int n,Q,nn; struct la{ int gr,h[N],nxt[N],to[N],w[N]; inline void tu(int x,int y,int c=0){to[++gr]=y,nxt[gr]=h[x],h[x]=gr,w[gr]=c;} }R,F; int K[N],cnt,tim,dfn[N]; int ff[N][24],m,dep[N],zhe[N][24],dwn[N][24]; int sta[N],top,f[N],g[N],bit[N]; vector<int> son[N]; bool cmp2(const int &a,const int &b){return f[a]>f[b];} void dfs(int u,int fa){ dfn[u]=++tim;dep[u]=dep[fa]+1; ff[u][0]=fa; rep(i,1,m){ ff[u][i]=ff[ff[u][i-1]][i-1]; if(!ff[u][i])break; } for(int i=R.h[u];i;i=R.nxt[i]){ int d=R.to[i]; if(d==fa)continue; dfs(d,u); if(f[d]+1>f[u])g[u]=f[u],f[u]=f[d]+1; else g[u]=max(g[u],f[d]+1); son[u].push_back(d); } if(son[u].size()>0)sort(son[u].begin(),son[u].end(),cmp2); for(int i=R.h[u];i;i=R.nxt[i]){ int d=R.to[i]; if(d==fa)continue; zhe[d][0]=(son[u][0]==d?g[u]:f[u])+1; dwn[d][0]=(son[u][0]==d?g[u]:f[u]); } } void beizeng(){ rep(i,1,m){ rep(u,1,n){ if(!ff[u][i])continue; zhe[u][i]=max(zhe[ff[u][i-1]][i-1]+bit[i-1],zhe[u][i-1]); dwn[u][i]=max(dwn[ff[u][i-1]][i-1],dwn[u][i-1]+bit[i-1]); } } } inline int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); for(int i=m;i>=0;--i)if(dep[ff[x][i]]>=dep[y])x=ff[x][i]; if(x==y)return x; for(int i=m;i>=0;--i)if(ff[x][i]!=ff[y][i])x=ff[x][i],y=ff[y][i]; return ff[x][0]; } bool cmp(int x,int y){return dfn[x]<dfn[y];} int dis[N],ans; bool is[N],in[N]; void dp_up(int u){ if(is[u])dis[u]=0; else dis[u]=0x3f3f3f3f; for(int i=F.h[u];i;i=F.nxt[i]){ int d=F.to[i]; dp_up(d); dis[u]=min(dis[u],dis[d]+F.w[i]); } } int btw(int u,int d){ for(int i=0;i<=m;++i)if(d&bit[i])u=ff[u][i]; return u; } void get_up(int u,int d,int k){ if(!d)return; int t=0; for(int i=0;i<=m;++i)if(d&bit[i]){ ans=max(ans,t+k+zhe[u][i]); u=ff[u][i],t+=bit[i]; } } void get_dwn(int u,int d,int k){ if(d<=0)return; for(int i=0;i<=m;++i)if(d&bit[i]){ d-=bit[i],ans=max(ans,k+d+dwn[u][i]); u=ff[u][i]; if(!d)return; } } int que[N],r; void dp_dwn(int u){ int tmp=0,now;ans=max(ans,dis[u]);//printf("%d %d\n",u,dis[u]); for(int i=F.h[u];i;i=F.nxt[i]){ int d=F.to[i]; dis[d]=min(dis[d],dis[u]+F.w[i]); dp_dwn(d); tmp=(dis[u]-dis[d]+F.w[i])/2; if(F.w[i]>1){ if(tmp==F.w[i])get_up(d,tmp-1,dis[d]); else if(tmp==0)get_dwn(d,F.w[i]-1,1+dis[u]); else{ now=btw(d,tmp); get_up(d,tmp,dis[d]); get_dwn(now,F.w[i]-tmp-1,dis[u]+1); } now=btw(d,F.w[i]-1); in[now]=1; que[++r]=now; } } } void get_son(int u){ rep(i,0,(int)(son[u].size()-1)){ if(!in[son[u][i]]){ans=max(ans,dis[u]+f[son[u][i]]+1);break;} } for(int i=F.h[u];i;i=F.nxt[i]){ int d=F.to[i]; get_son(d); } F.h[u]=0; in[u]=0; } int main(){ freopen("inception.in","r",stdin); freopen("inception.out","w",stdout); scanf("%d%d",&n,&Q); m=log2(n); int u,v; rep(i,2,n)scanf("%d%d",&u,&v),R.tu(u,v),R.tu(v,u); bit[0]=1; rep(i,1,m)bit[i]=bit[i-1]<<1; dfs(1,0); beizeng(); while(Q--){ scanf("%d",&cnt); rep(i,1,cnt)scanf("%d",&K[i]),is[K[i]]=1; sort(K+1,K+cnt+1,cmp); F.gr=0;ans=0; sta[top=1]=1;//默認讓1來作虛樹的根,會省去一些麻煩 in[1]=1; rep(i,1,cnt){ if(K[i]==1)continue; int tmp=lca(sta[top],K[i]); in[K[i]]=1; if(tmp==sta[top]){sta[++top]=K[i];continue;} while(top>1&&dfn[sta[top-1]]>=dfn[tmp]){ F.tu(sta[top-1],sta[top],dep[sta[top]]-dep[sta[top-1]]); top--; } if(sta[top]!=tmp)F.tu(tmp,sta[top],dep[sta[top]]-dep[tmp]),sta[top]=tmp,in[tmp]=1; sta[++top]=K[i]; } while(top>1)F.tu(sta[top-1],sta[top],dep[sta[top]]-dep[sta[top-1]]),top--; dp_up(1); dp_dwn(1); get_son(1); printf("%d\n",ans); //clear_is,gr rep(i,1,cnt)is[K[i]]=0; rep(i,1,r)in[que[i]]=0; r=0; } return 0; }