这题太变态了吧。
分析
我们预处理出每个帮派的lca节点,当帮派合并的时候,我们就可以求各个帮派的lca的节点。
假设首都节点是u,各个帮派的lca是pos,分两种情况
当lca(u,pos) != pos的时候,说明u不在pos的子树下,答案就是dis(u,pos)。
当lca(u,pos) == pos的时候,说明u在pos的子树下,首先我们明确一点,对于帮派控制的节点,它与u的lca一定是pos的子节点,我们对每个联盟的帮派求离u最近的dfs序的节点,答案就是dis(u,lca(u,v))。
求最近的dfs序可以利用二分。
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define int long long
const int inf = 0x3f3f3f3f;
const int maxn = 501110;
const int M = 1e9+7;
int n,k,q,t = 20;
int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return f*x;
}
void print(int x)
{
if(x < 0) {putchar('-');x = -x;}
if(x/10) print(x/10);
putchar(x%10+'0');
}
int head[maxn],to[maxn*2],Next[maxn*2],cnt = 2;
void add(int u,int v)
{
to[cnt] = v;Next[cnt] = head[u];head[u] = cnt;cnt++;
}
vector<int> v[maxn]; //帮派
int fa[maxn][25],d[maxn],top[maxn];
int dfn[maxn],tim; //dfs序列,第几个访问到的
void dfs(int u,int pre)
{
dfn[u] = ++tim;
d[u] = d[pre]+1;
fa[u][0] = pre;
for(int i = 1; (1ll<<i) <= d[u]; i++)
{
fa[u][i] = fa[fa[u][i-1]][i-1];
}
for(int i = head[u]; i ; i = Next[i])
{
int v = to[i];
if(v == pre) continue;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(d[x] > d[y]) swap(x,y);
for(int i = t; i >= 0; i--)
{
if(d[fa[y][i]] >= d[x]) y = fa[y][i];
}
if(x == y) return x;
for(int i = t; i >= 0; i--)
{
if(fa[y][i] != fa[x][i])
{
y = fa[y][i];
x = fa[x][i];
}
}
return fa[x][0];
}
int dist(int x,int y)
{
return d[x]+d[y]-2*d[lca(x,y)];
}
bool cmp(int x,int y)
{
return dfn[x] < dfn[y];
}
signed main()
{
n = read();
for(int i = 1,x,y; i < n; i++)
{
x = read(), y = read();
add(x,y);
add(y,x);
}
dfs(1,0);
k = read();
for(int i = 1,sz; i <= k; i++)
{
sz = read();
for(int j = 1,x; j <= sz; j++)
{
x = read();
v[i].push_back(x);
if(top[i] == 0) top[i] = x;
else top[i] = lca(top[i],x);
}
sort(v[i].begin(),v[i].end(),cmp);
}
q = read();
vector<int> vt;
for(int i = 1,u,sz; i <= q; i++)
{
u = read(),sz = read();
int pos = 0;
vt.clear();
for(int j = 1,x; j <= sz; j++)
{
x = read();
vt.push_back(x);
if(pos == 0) pos = top[x];
else pos = lca(pos,top[x]);
}
int ff = lca(u,pos);
int ans = inf;
if(ff != pos) //不在子树
{
ans = dist(u,pos);
}
else //在子树里面
{
for(auto node : vt)
{
int l = 0,r = v[node].size()-1;
pos = r;
while(l <= r)
{
int mid = (l+r)/2;
if(dfn[v[node][mid]] >= dfn[u])
{
pos = mid;
r = mid-1;
}
else l = mid+1;
}
ans = min(ans,dist(u,lca(u,v[node][pos])));
if(pos) ans = min(ans,dist(u,lca(u,v[node][pos-1])));
}
}
print(ans);putchar('\n');
}
return 0;
} 
京公网安备 11010502036488号