题目:BZOJ3572.
题目大意:给定一棵
n
n
n个点的树与一些询问,每次询问给定
k
k
k个点
a
i
a_i
ai.现在定义一个点从属于距离它最近的
a
i
a_i
ai,若距离相等则属于编号最小的
a
i
a_i
ai,要求输出对于每个
a
i
a_i
ai有多少点属于
a
i
a_i
ai.
1
≤
n
,
∑
k
≤
3
∗
1
0
5
1\leq n,\sum k\leq3*10^5
1≤n,∑k≤3∗105.
首先建出虚树,发现这题不在虚树上的信息并不是很好处理.
考虑先求出虚树上每个点属于哪个点,可以类比换根DP通过两遍dfs实现.
接下来考虑不在虚树上的点.先dfs整棵虚树,dfs点 k k k的时候我们算出整棵以 k k k为根的子树对答案的贡献.
先假设 k k k的整棵子树都属于 k k k所属的节点.之后对于 k k k的每个儿子 y y y,若 k k k所属的节点与 y y y所属节点是同一个,那么我们只去掉 y y y子树的贡献,在下面的dfs中重新计算 y y y的贡献.
否则的话,必然存在 y y y到 k k k路径上的一个分界点 z z z使得在这之下的都属于 y y y所属节点且在 z z z之上的都属于 k k k所属节点,现在的问题是如何找到 z z z.
显然,我们 k k k到其所属节点的距离、 y y y到其所属节点的距离与 k , y k,y k,y的距离就可以求出 z z z是 y y y的多少级祖先了,有了距离后用树上倍增就可以得到 z z z了.
然后这个问题就解决啦然而细节很多代码巨难写,时间复杂度
O
(
(
n
+
∑
k
)
log
n
)
O((n+\sum k)\log n)
O((n+∑k)logn).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=300000,C=20,INF=(1<<30)-1;
int n,m;
struct side{
int y,next;
}e[N*4+9];
int lin[2][N+9],cs;
void Ins(int id,int x,int y){e[++cs].y=y;e[cs].next=lin[id][x];lin[id][x]=cs;}
int dep[N+9],siz[N+9],gr[N+9][C];
int dfs[N+9],co;
void Dfs_doubly(int k,int fa){
gr[k][0]=fa;
dep[k]=dep[fa]+1;
siz[k]=1;
dfs[k]=++co;
for (int i=1;i<C;++i)
gr[k][i]=gr[gr[k][i-1]][i-1];
for (int i=lin[0][k];i;i=e[i].next)
if (e[i].y^fa){
Dfs_doubly(e[i].y,k);
siz[k]+=siz[e[i].y];
}
}
int Query_lca(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int i=C-1;i>=0;--i)
if (dep[gr[x][i]]>=dep[y]) x=gr[x][i];
if (x==y) return x;
for (int i=C-1;i>=0;--i)
if (gr[x][i]^gr[y][i]) x=gr[x][i],y=gr[y][i];
return gr[x][0];
}
int Query_anc(int x,int v){
for (int i=C-1;i>=0;--i)
if (v>=1<<i) x=gr[x][i],v-=1<<i;
return x;
}
int Query_dis(int x,int y){return dep[x]+dep[y]-2*dep[Query_lca(x,y)];}
int ca,a[N+9],ta[N+9],lca[N+9],tag[N+9];
int st[N+9],cst;
bool cmp(const int &a,const int &b){return dfs[a]<dfs[b];}
void Build(){
for (int i=1;i<=ca;++i) ta[i]=a[i];
sort(ta+1,ta+ca+1,cmp);
st[cst=1]=ta[0]=1;
for (int i=1;i<=ca;++i){
lca[i]=Query_lca(ta[i],ta[i-1]);
lin[1][lca[i]]=tag[lca[i]]=0;
}
for (int i=1;i<=ca;++i) lin[1][ta[i]]=0,tag[ta[i]]=1;
for (int i=1;i<=ca;++i){
for (;cst>1&&dep[lca[i]]<dep[st[cst-1]];--cst)
Ins(1,st[cst-1],st[cst]);
if (st[cst]^lca[i]){
Ins(1,lca[i],st[cst]);
if (st[--cst]^lca[i]) st[++cst]=lca[i];
}
if (st[cst]^ta[i]) st[++cst]=ta[i];
}
for (;cst>1;--cst) Ins(1,st[cst-1],st[cst]);
}
int bel[N+9],md[N+9];
void Dfs_bel1(int k){
bel[k]=md[k]=INF;
if (tag[k]) bel[k]=k,md[k]=0;
for (int i=lin[1][k];i;i=e[i].next){
Dfs_bel1(e[i].y);
int t=Query_dis(k,bel[e[i].y]);
if (t<md[k]||t==md[k]&&bel[e[i].y]<bel[k]) bel[k]=bel[e[i].y],md[k]=t;
}
}
void Dfs_bel2(int k){
for (int i=lin[1][k];i;i=e[i].next){
int t=Query_dis(e[i].y,bel[k]);
if (t<md[e[i].y]||t==md[e[i].y]&&bel[k]<bel[e[i].y]) bel[e[i].y]=bel[k],md[e[i].y]=t;
Dfs_bel2(e[i].y);
}
}
int ans[N+9];
void Dfs_ans(int k){
ans[bel[k]]+=siz[k];
for (int i=lin[1][k];i;i=e[i].next){
if (bel[k]==bel[e[i].y]) ans[bel[k]]-=siz[e[i].y];
else{
int t=Query_dis(k,e[i].y)-1+md[k]-md[e[i].y]>>1;
if (Query_dis(bel[k],bel[e[i].y])&1^1&&bel[e[i].y]<bel[k]) ++t;
t=Query_anc(e[i].y,t);
ans[bel[k]]-=siz[t];
ans[bel[e[i].y]]+=siz[t]-siz[e[i].y];
}
Dfs_ans(e[i].y);
}
}
Abigail into(){
scanf("%d",&n);
for (int i=1;i<n;++i){
int x,y;
scanf("%d%d",&x,&y);
Ins(0,x,y);Ins(0,y,x);
}
}
Abigail work(){
Dfs_doubly(1,0);
}
Abigail getans(){
scanf("%d",&m);
for (int i=1;i<=m;++i){
scanf("%d",&ca);
for (int j=1;j<=ca;++j)
scanf("%d",&a[j]);
Build();
Dfs_bel1(1);
Dfs_bel2(1);
for (int i=1;i<=ca;++i) ans[a[i]]=0;
Dfs_ans(1);
for (int i=1;i<=ca;++i)
printf("%d ",ans[a[i]]);
puts("");
}
}
int main(){
into();
work();
getans();
return 0;
}