一、题目
二、解法
这道题一看就是虚树,我们先把虚树建出来,可惜这道题难点并不在此。
设
d
p
[
u
]
dp[u]
dp[u]表示离
u
u
u最近的关键点,我们可以用
p
a
i
r
pair
pair表示
d
p
dp
dp,距离为第一关键字,编号为第二关键字,就可以直接用大于符号比较了,这个
d
p
dp
dp就跑两遍,比较简单。
难点在于统计答案,我们先把离
u
u
u最近的关键点的答案加上
u
u
u实际子树的大小,这里分类讨论一下。
- 如果 u u u的最近关键点和 v v v的最近关键点是一个点,那么这条虚边都贡献给该关键点。
-
o
t
h
e
r
w
i
s
e
otherwise
otherwise,我们考虑划分
u
,
v
u,v
u,v的势力范围,请看下图:
我们把这三条边的长度求和,然后除 2 2 2减去 ( v , x v ) (v,x_v) (v,xv)的距离,这里需要特判距离和为奇数的情况,如果这样的话我们就要考虑最中间的点划给谁,这个由编号决定,得到了距离之后我们就倍增求出 v v v管辖的最远点,然后算贡献就行了。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),献上我要调吐了的代码。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#define f first
#define s second
#define mp make_pair
#define pair pair<int,int>
using namespace std;
const int MAXN = 300005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,q,k,k1,k2,tot,cnt,f[MAXN],dep[MAXN],dfin[MAXN],dfou[MAXN];
int ans[MAXN],siz[MAXN],fa[MAXN][20],b[MAXN],a[MAXN*2],vis[MAXN],pd[MAXN];
pair dp[MAXN];
vector<int> G[MAXN];
stack<int> S;
struct edge
{
int v,next;
}e[2*MAXN];
bool cmp(int a,int b)
{
int t1=a>0?dfin[a]:dfou[-a];
int t2=b>0?dfin[b]:dfou[-b];
return t1<t2;
}
void dfs1(int u,int p)
{
fa[u][0]=p;
siz[u]=1;
for(int i=1;i<20;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
dfin[u]=++cnt;
dep[u]=dep[p]+1;
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==p) continue;
dfs1(v,u);
siz[u]+=siz[v];
}
dfou[u]=++cnt;
}
int get(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=19;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
u=fa[u][i];
if(u==v) return u;
for(int i=19;i>=0;i--)
if(fa[u][i]^fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
void dfs2(int u,int p)
{
dp[u].f=0x3f3f3f3f;
if(pd[u]) dp[u]=mp(0,u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==p) continue;
dfs2(v,u);
pair t=mp(dp[v].f+dep[v]-dep[u],dp[v].s);
if(dp[u]>t)
dp[u]=t;
}
}
void dfs3(int u,int p)
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==p) continue;
pair t=mp(dp[u].f+dep[v]-dep[u],dp[u].s);
if(dp[v]>t) dp[v]=t;
dfs3(v,u);
}
}
void dfs4(int u,int p)
{
ans[dp[u].s]+=siz[u];
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==p) continue;
dfs4(v,u);
int len,to,cur;
if(dp[u].s==dp[v].s)
{
ans[dp[u].s]-=siz[v];
goto In;
}
len=dp[u].f+dp[v].f+dep[v]-dep[u]-1;
to=len/2-dp[v].f,cur=v;
if(len&1==1 && dp[u].s>dp[v].s)
to++;
for(int j=19;j>=0;j--)
if((1<<j)<=to)
to-=1<<j,cur=fa[cur][j];
ans[dp[u].s]-=siz[cur];
ans[dp[v].s]+=siz[cur]-siz[v];
In:;
vis[v]=pd[v]=0;
G[v].clear();
}
}
int main()
{
n=read();
for(int i=2;i<=n;i++)
{
int u=read(),v=read();
e[++tot]=edge{v,f[u]},f[u]=tot;
e[++tot]=edge{u,f[v]},f[v]=tot;
}
dfs1(1,0);
q=read();
while(q--)
{
k=k1=k2=read();
for(int i=1;i<=k;i++)
{
a[i]=b[i]=read();
vis[a[i]]=pd[a[i]]=1;
ans[a[i]]=0;
}
sort(a+1,a+1+k,cmp);
for(int i=1;i<k1;i++)
{
int t=get(a[i],a[i+1]);
if(!vis[t]) a[++k]=t,vis[t]=1;
}
if(!vis[1]) a[++k]=1,vis[1]=1;
k1=k;
for(int i=1;i<=k1;i++)
a[++k]=-a[i];
sort(a+1,a+1+k,cmp);
for(int i=1;i<=k;i++)
{
if(a[i]>0)
S.push(a[i]);
else
{
int t=S.top();S.pop();
if(t==1) break;
G[t].push_back(S.top());
G[S.top()].push_back(t);
}
}
dfs2(1,0);
dfs3(1,0);
dfs4(1,0);
for(int i=1;i<=k2;i++)
printf("%d ",ans[b[i]]);
puts("");
pd[1]=vis[1]=0;G[1].clear();
}
}