https://www.lydsy.com/JudgeOnline/problem.php?id=3572
http://hzwer.com/6804.html 写的时候参考了hzwer的代码,不会写的题读一遍代码就好了(所以菜)。
虚树还是老一套,树形dp的部分比较有趣。
通过dfs两遍(从下往上总结一遍,从上往下再一遍)把每个点所归属的点找到。
对于那些没有出现在虚树中的点,对通过每条虚树上的边进行总结找到每两个点之间没有统计的点的归属(这个归属一定为bel[x]或bel[y])。
通过倍增中用lca找到距离判断来找每条边上分割点(可以发现需要找的是那种 bel[x] 和 bel[y] 在边两边的边, bel[x] 和 bel[y] 不在边两边时一定 bel[x] = bel[y] ),
那么对 bel[x] 的贡献为:siz[x在这条边上的第一个孩子] - siz[分割点] ,
对 bel[y] 的贡献为:siz[分割点] - siz[y] 。
还要注意一下那些作为某个虚树中的点的子树出现的点块,这些点是属于它的根(姑且这么说吧)的归属的,这部分贡献是在对边的统计结束后在统计虚树中每个点的归属时计算的。
说起来有点麻烦,读代码吧。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
using namespace std;
#define LL long long
const int maxn=;
int n,m,Q;
struct nod{
int y,next;
}e[maxn*];
int head[maxn]={},tot=;
int dep[maxn]={},id[maxn]={},siz[maxn]={},fa[maxn][]={},cnt=;
int a[maxn]={},bel[maxn]={},sta[maxn]={},tai=;
int c[maxn]={},re[maxn],tly=;
int f[maxn]={},b[maxn]={};
inline void init(int x,int y){e[++tot].y=y;e[tot].next=head[x];head[x]=tot;}
bool mcmp(int x,int y){
return id[x]<id[y];
}
void dfs(int x){
int y; siz[x]=; id[x]=++cnt;
for(int i=;i<=;i++)fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=e[i].next){
y=e[i].y; if(y==fa[x][])continue;
fa[y][]=x; dep[y]=dep[x]+; dfs(y);
siz[x]+=siz[y];
}
}
inline int getlca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=;i>=;--i)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=;i>=;i--)if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}
return fa[x][];
}
inline int getdis(int x,int y){
return dep[x]+dep[y]-*dep[getlca(x,y)];
}
void dfs1(int x){//get every points'bel[]
c[++tly]=x;re[x]=siz[x];
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
dfs1(y);if(bel[y]==)continue;
if(bel[x]==){bel[x]=bel[y];continue;}
int d1=getdis(bel[y],x),d2=getdis(bel[x],x);
if(d1<d2||(d1==d2&&bel[y]<bel[x]))bel[x]=bel[y];
}
}
void dfs2(int x){
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
if(bel[y]==)bel[y]=bel[x];
else{
int d1=getdis(bel[y],y),d2=getdis(bel[x],y);
if(d1>d2||(d1==d2&&bel[y]>bel[x]))bel[y]=bel[x];
}
dfs2(y);
}
}
void doit(int x,int y){
int son=y,mid=y;
for(int i=;i>=;--i)
if(dep[fa[son][i]]>dep[x])son=fa[son][i];
//cout<<x<<y<<son<<endl;
re[x]-=siz[son];
if(bel[x]==bel[y]){f[bel[x]]+=siz[son]-siz[y];return;}
for(int i=;i>=;--i){
int nxt=fa[mid][i];
if(dep[nxt]<dep[son])continue;
int d1=getdis(nxt,bel[x]),d2=getdis(nxt,bel[y]);
if(d1>d2||(d1==d2&&bel[y]<bel[x]))mid=nxt;
}
f[bel[x]]+=siz[son]-siz[mid];
f[bel[y]]+=siz[mid]-siz[y];
}
void solve(){
tot=;tly=;
scanf("%d",&m);
for(int i=;i<=m;i++){scanf("%d",&a[i]);b[i]=a[i];bel[a[i]]=a[i];}
sort(a+,a++m,mcmp);
if(a[]!=)sta[++tai]=;
sta[++tai]=a[];
for(int i=;i<=m;i++){
int lc=getlca(sta[tai],a[i]);
while(dep[sta[tai]]>dep[lc]){
if(dep[sta[tai-]]<=dep[lc]){init(lc,sta[tai]);--tai;break;}
init(sta[tai-],sta[tai]);tai--;
}
if(lc!=sta[tai])sta[++tai]=lc;
if(a[i]!=sta[tai])sta[++tai]=a[i];
}
while(--tai)init(sta[tai],sta[tai+]);
dfs1();dfs2();
for(int i=;i<=tly;i++){
for(int j=head[c[i]];j;j=e[j].next){
doit(c[i],e[j].y);
}
}
for(int i=;i<=tly;i++)f[bel[c[i]]]+=re[c[i]];
for(int i=;i<m;i++)printf("%d ",f[b[i]]);
printf("%d\n",f[b[m]]);
for(int i=;i<=tly;i++){head[c[i]]=;bel[c[i]]=;f[c[i]]=;re[c[i]]=;}
}
int main(){
//freopen("a.in","r",stdin);
scanf("%d",&n);
int x,y;
for(int i=;i<n;i++){scanf("%d%d",&x,&y);init(x,y);init(y,x);}
dep[]=;dfs();
scanf("%d",&Q);
memset(head,,sizeof(head));
for(int i=;i<=Q;i++)solve();
return ;
}