题意

看见数据范围就知道是虚树,于是先建出虚树。

考虑先求出虚树上的点的管理点,显然两边dfs,一遍从下往上,一遍从上往下。

之后考虑不在虚树上的点,对于虚树上的每一条边\((u,v)\),我们考虑上面未出现在虚树上的点的个数是多少,显然是\(u\)包含\(v\)的儿子\(x\)的子树的大小减去\(v\)子树的大小,这个可以倍增求出。

考虑\(u,v\)两点的管理点是否相等,如果相等那么直接加上\(size[x]-size[v]\)即可,不相等\(u->v\)就必定存在一个分界点,于是我们可以倍增求出。

这时还会有考虑不到的点,用个数组\(g[x]\)记下x的子树中有多少点未被分配,之后并到\(x\)上。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=300010;
int n,m,cnt,tim,top,t,num;
int head[maxn],a[maxn],sta[maxn],dfn[maxn],dep[maxn],ans[maxn],size[maxn],b[maxn],c[maxn],col[maxn],g[maxn];
int f[maxn][20];
struct edge{int to,nxt;}e[maxn<<1];
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
inline void add(int u,int v)
{
e[++cnt].nxt=head[u];
head[u]=cnt;
e[cnt].to=v;
}
void dfs_pre(int x,int fa)
{
dep[x]=dep[fa]+1;size[x]=1;dfn[x]=++tim;
for(int i=1;i<=t;i++)f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa)continue;
f[y][0]=x;dfs_pre(y,x);size[x]+=size[y];
}
}
inline int lca(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=t;~i;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i];
if(x==y)return x;
for(int i=t;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
inline int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
void dfs1(int x)
{
c[++num]=x;g[x]=size[x];
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
dfs1(y);
if(!col[y])continue;
if(!col[x]){col[x]=col[y];continue;}
int d1=dis(col[y],x),d2=dis(col[x],x);
if(d1<d2||(d1==d2&&col[y]<col[x]))col[x]=col[y];
}
}
void dfs2(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!col[y])col[y]=col[x];
else
{
int d1=dis(col[y],y),d2=dis(col[x],y);
if(d1>d2||(d1==d2&&col[x]<col[y]))col[y]=col[x];
}
dfs2(y);
}
}
inline void work(int x,int y)
{
int now=y;
for(int i=t;~i;i--)if(dep[now]-(1<<i)>dep[x])now=f[now][i];
g[x]-=size[now];
if(col[x]==col[y]){ans[col[x]]+=size[now]-size[y];return;}
int tmp=y;
for(int i=t;~i;i--)
{
int nxt=f[tmp][i];
if(dep[nxt]<=dep[x])continue;
int d1=dis(nxt,col[x]),d2=dis(nxt,col[y]);
if(d1>d2||(d1==d2&&col[y]<col[x]))tmp=nxt;
}
ans[col[x]]+=size[now]-size[tmp],ans[col[y]]+=size[tmp]-size[y];
}
inline void solve()
{
num=cnt=0;
int tot;scanf("%d",&tot);
for(int i=1;i<=tot;i++)scanf("%d",&a[i]),b[i]=a[i],col[a[i]]=a[i];
sta[top=1]=1;head[1]=0;
sort(a+1,a+tot+1,cmp);
for(int i=1;i<=tot;i++)
{
if(a[i]==1)continue;
int x=lca(sta[top],a[i]);
if(x!=sta[top])
{
while(top>1&&dfn[sta[top-1]]>dfn[x])add(sta[top-1],sta[top]),top--;
if(x!=sta[top-1])head[x]=0,add(x,sta[top]),sta[top]=x;
else add(x,sta[top--]);
}
head[a[i]]=0,sta[++top]=a[i];
}
for(int i=1;i<top;i++)add(sta[i],sta[i+1]);
dfs1(1),dfs2(1);
for(int j=1;j<=num;j++)
for(int i=head[c[j]];i;i=e[i].nxt)
work(c[j],e[i].to);
for(int i=1;i<=num;i++)ans[col[c[i]]]+=g[c[i]];
for(int i=1;i<=tot;i++)printf("%d ",ans[b[i]]);
puts("");
for(int i=1;i<=num;i++)ans[c[i]]=g[c[i]]=col[c[i]]=0;
}
int main()
{
scanf("%d",&n);t=(int)log2(n)+1;
for(int i=1;i<n;i++)
{
int u,v;scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs_pre(1,0);
scanf("%d",&m);
for(int i=1;i<=m;i++)solve();
return 0;
}

luoguP3233 [HNOI2014]世界树的更多相关文章

  1. [BZOJ3572][Hnoi2014]世界树

    [BZOJ3572][Hnoi2014]世界树 试题描述 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条 ...

  2. BZOJ 3572: [Hnoi2014]世界树

    BZOJ 3572: [Hnoi2014]世界树 标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增 Time Limit: 20 Sec Memory Limit: 512 ...

  3. bzoj 3572: [Hnoi2014]世界树 虚树 && AC500

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 520  Solved: 300[Submit][Status] ...

  4. bzoj 3572 [Hnoi2014]世界树(虚树+DP)

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status] ...

  5. 【BZOJ3572】[Hnoi2014]世界树 虚树

    [BZOJ3572][Hnoi2014]世界树 Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森 ...

  6. bzoj3572[Hnoi2014] 世界树 虚树+dp+倍增

    [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1921  Solved: 1019[Submit][Status][Dis ...

  7. <虚树+树型DP> HNOI2014世界树

    <虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...

  8. [题解] [HNOI2014] 世界树

    题面 [HNOI2014]世界树 题解 从数据范围很容易看出是个虚树DP(可惜看出来了也还是不会做) 虚树大家应该都会, 不会的话自己去搜吧, 我懒得讲了, 我们在这里只需要考虑如何DP即可 首先我们 ...

  9. [HNOI2014]世界树

    题目描述 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基 ...

随机推荐

  1. poj 2456 Aggressive cows 二分 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2456 解法 使用二分逐个尝试间隔距离 能否满足要求 检验是否满足要求的函数 使用的思想是贪心 第一个点放一头牛 后面大于等于尝试的距离才放 ...

  2. xpath:

    from selenium import webdriverb = webdriver.Firefox()#路径读取方式一:# b.get(r"C:\我的代码\selenium自动化测试\t ...

  3. Java之Random类

    什么是Random类 此类的实例用于生成伪随机数,使用此类中的方法能够得到一个随机数. Random使用步骤 查看类 java.util.Random :该类需要 import导入使后使用. 查看构造 ...

  4. 记MacOs视频mov与mp4格式转换问题解决

    综述 记录了mov转mp4格式的方法 记录了自己是多蠢 问题背景 这学期选修的<工程英语视听说>课,需要提交一段口语考试视频,于是乎: 带着我的大疆Mavic Mini 和iPad Pro ...

  5. Python画一棵漂亮的樱花树(不同种樱花+玫瑰+圣诞树喔)

    不少用Python(大多是turtle库)绘制的树图,感觉很漂亮,我整理了一下,挑了一些我觉得不错的代码分享给大家(这些我都测试过,确实可以生成喔~)one 樱花树 动态生成樱花效果图(这个是动态的) ...

  6. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 10

    18.8  设计完美分页类 数据记录列表几乎出现在Web项目的每个模块中,假设一张表中有十几万条记录,我们不可能一次全都显示出来,当然也不能仅显示几十条.为了解决这样的矛盾,通常在读取时设置以分页的形 ...

  7. CNN反向传播更新权值

    背景 反向传播(Backpropagation)是训练神经网络最通用的方法之一,网上有许多文章尝试解释反向传播是如何工作的,但是很少有包括真实数字的例子,这篇博文尝试通过离散的数据解释它是怎样工作的. ...

  8. OpenGL入门1.7:摄像机

    每一个小步骤的源码都放在了Github 的内容为插入注释,可以先跳过 前言 我们已经知道了何为观察矩阵以及如何使用观察矩阵移动场景(我们向后移动了一点) OpenGL本身没有摄像机(Camera)的概 ...

  9. java高并发系列 - 第10天:线程安全和synchronized关键字

    这是并发系列第10篇文章. 什么是线程安全? 当多个线程去访问同一个类(对象或方法)的时候,该类都能表现出正常的行为(与自己预想的结果一致),那我们就可以所这个类是线程安全的. 看一段代码: pack ...

  10. hash算法原理及应用漫谈【加图版】

    原文:https://blog.csdn.net/Tencent_TEG/article/details/103021226 提到hash,相信大多数同学都不会陌生,之前很火现在也依旧很火的技术区块链 ...