題目
虛樹顯然,
一次從下到上求子樹內能到該點的最優的臨時議事處。
一次從上到下求子樹外能到點的父親的最優的臨時議事處。
然後兩個加一下除個二,
樹上找級祖先即可。
長鏈剖分求級祖先:
先預處理所有點的級祖先。
再對於每個長鏈鏈頭,處理鏈頭向上長鏈長度級的父親數組。
那麼我們對於求的級父親。
先跳步,其中
然後我們再跳步,到達點一定在現在的在的長鏈所記錄的或者就在這一條長鏈上,算即可。
這個過程除了預處理都是可以
但是好像沒有純樹剖快
#include<bits/stdc++.h>
#define maxn 300005
#define lim 19
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define ADJ(i,u) for(int i=info[u],v;i;i=Prev[i])
#define Ct const
#define inf 0x3f3f3f3f
using namespace std;
char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){char ch;
for(;!isdigit(ch=getc()););
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
int tg[maxn<<2],*g[maxn]={tg},f[lim][maxn],lg[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int len[maxn],tp[maxn],sonz[maxn],sonl[maxn],sz[maxn],fa[maxn],dep[maxn],dfn[maxn];
void dfs(int u,int ff){
dep[u]=dep[f[0][u]=fa[u]=ff]+(sz[u]=1);
ADJ(i,u) if((v=to[i])^ff){
dfs(v,u),sz[u]+=sz[v],(sz[v]>sz[sonz[u]]) && (sonz[u] = v);
(len[v]>len[sonl[u]]) && (sonl[u] = v);
}
len[u]=len[sonl[u]]+1;
}
void dfs2(int u,int ff){
dfn[u]=++dfn[0];
*g[u]=u;
ADJ(i,u)
if((v=to[i])^ff)
tp[v]=v==sonz[u]?tp[u]:v;
if(int v=sonl[u]) g[v]=g[u]+1,dfs2(v,u);
ADJ(i,u)
if((v=to[i])^ff && v^sonl[u]){
g[v]=g[0]+len[v],g[0]+=2*len[v];
for(int j=1,p=fa[v];j<=len[v] && p;j++,p=fa[p])
*(g[v]-j)=p;
dfs2(v,u);
}
}
int LCA(int u,int v){
for(;tp[u]^tp[v];u=fa[tp[u]]) if(dep[tp[u]]<dep[tp[v]]) swap(u,v);
return dep[u]<dep[v]?u:v;
}
int getk(int u,int k){
if(!k) return u;
int t = lg[k];
u = f[t][u];
return *(g[u] - (k-(1<<t)));
}
inline bool cmp(Ct int &u,Ct int &v){ return dfn[u] < dfn[v]; }
struct data{
int a,b;data(int a=0,int b=0):a(a),b(b){}
bool operator <(Ct data &B)Ct{ return a==B.a?b<B.b:a<B.a; }
data operator +(Ct int &B)Ct{ return data(a+B,b); }
}dp[2][maxn],dpl[maxn],dpr[maxn];
int ont[maxn],ans[maxn],ts[maxn];
void ser(int u){
if(ont[u]) dp[0][u]=data(0,u);
else dp[0][u]=data(inf,0);
ts[u]=0;
ADJ(i,u){
ser(v=to[i]);int w = dep[v] - dep[u];
dp[0][u]=min(dp[0][u],dp[0][v]+w);
ts[u] += sz[getk(v,w-1)];
}
}
void ser2(int u,bool fl=0){
static int q[maxn]={},R=0;
int p=0;
if(ont[u]) dp[1][u] = data(0,u);
dpl[p] = dp[1][u];
ADJ(i,u){
v=to[i];
dpl[v] = min(dpl[p],dp[0][v]+(dep[v]-dep[u]));
p = q[++R] = v;
}
dpr[p=0]=dp[1][u];
for(;R;){
int v = q[R--];
data t = min(dpr[p] , dpl[q[R]]);
int H = min(max((t.a + dp[0][v].a + dep[v] - dep[u] - 1 + (dp[0][v].b < t.b)) / 2 - dp[0][v].a , -1) , dep[v] - dep[u] - 1);
int TS=(H==-1 ? ts[v] : sz[getk(v,H)]),HS=sz[getk(v,dep[v]-dep[u]-1)];
ans[dp[0][v].b] += TS - ts[v] , ans[t.b] += HS - TS;
// if(t.b==1) printf("%d %d %d %d %d %d %d %d %d %d %d\n",u,dp[0][v].b,dp[0][v].a,t.a,t.b,TS,ts[v],HS,ans[1],dep[v]-dep[u],t.a + dp[0][v].a + dep[v] - dep[u]);
dpr[v] = min(dpr[p],dp[0][v]+(dep[v]-dep[u]));
p = v;
dp[1][v]=t+(dep[v]-dep[u]);
}
ADJ(i,u){
v=to[i];
ser2(v);
}
if(fl){
ans[dp[0][u].b]+=sz[1]-ts[u];
}
}
int main(){
// /freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
int u,v,n,m;
read(n);
rep(i,1,n-1) read(u),read(v),Node(u,v),Node(v,u);
dfs(1,0),g[1]=g[0],g[0]+=len[1]+1,dfs2(tp[1]=1,0);
rep(j,1,lim-1) rep(i,1,n) f[j][i] = f[j-1][f[j-1][i]];
rep(i,2,n) lg[i] = lg[i>>1]+1;lg[0]=-1;
read(m);
memset(info,0,sizeof info),cnt_e=0;
static int q[maxn],ar[maxn],ay[maxn],pt[maxn],cnt=0,R=0,N;
for(;m--;){
read(N);
rep(i,0,N-1) read(ar[i]),ay[i]=ar[i],ont[ar[i]]=1;
sort(ar,ar+N,cmp);
rep(i,0,N-1){
if(R){ int t=LCA(ar[i],q[R]),p=0;
for(;R&&dep[q[R]]>dep[t];p=q[R--]) if(p) Node(q[R],p);
if(q[R]^t) q[++R]=pt[++cnt]=t;
if(p) Node(q[R],p);}
q[++R]=pt[++cnt]=ar[i];
}
for(int p=0;R;p=q[R--]) if(p) Node(q[R],p);
ser(q[1]),dp[1][q[1]]=dp[0][q[1]],ser2(q[1],1);
int sm = 0;
rep(i,0,N-1) printf("%d%c",ans[ay[i]]," \n"[i==N-1]);
for(;cnt;){
int t=pt[cnt--];
ont[t] = ans[t] = info[t] = 0;
}
}
}