http://www.lydsy.com/JudgeOnline/problem.php?id=3572

思路:建立虚树,然后可以发现,每条边不是同归属于一端,那就是切开,一半给上面,一半给下面。

 #include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define N 300005
int tot,go[N*],next[N*],first[N],sz,deep[N],tmp[N],tree[N];
int son[N],dfn[N],fa[N][],bin[],ask[N],In[N],st[N],n,m,ans[N];
int father[N],val[N];
std::pair<int,int>near[N];
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
void insert(int x,int y){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
}
void add(int x,int y){
insert(x,y);insert(y,x);
}
void dfs(int x){
son[x]=;
dfn[x]=++sz;
for (int i=;i<=;i++)
fa[x][i]=fa[fa[x][i-]][i-];
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur==fa[x][]) continue;
deep[pur]=deep[x]+;
fa[pur][]=x;
dfs(pur);
son[x]+=son[pur];
}
}
int find(int x,int dep){
for (int i=;i>=;i--)
if (deep[fa[x][i]]>=dep) x=fa[x][i];
return x;
}
int lca(int x,int y){
if (deep[x]<deep[y]) std::swap(x,y);
int t=deep[x]-deep[y];
for (int i=;i<=;i++)
if (t&bin[i])
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][];
}
bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
void solve(){
m=read();
for (int i=;i<=m;i++){
ask[i]=read(),tmp[i]=tree[i]=ask[i];
near[ask[i]]=std::make_pair(,ask[i]);
ans[ask[i]]=;
}
std::sort(ask+,ask++m,cmp);
int top=,all=m;
for (int i=;i<=m;i++){
int p=ask[i];
if (!top) father[p]=,st[++top]=p;
else{
int x=lca(st[top],p);
father[p]=x;
while (top&&deep[st[top]]>deep[x]){
if (deep[st[top-]]<=deep[x]){
father[st[top]]=x;
}
top--;
}
if (st[top]!=x){
father[x]=st[top];tree[++all]=x;
st[++top]=x;near[x]=std::make_pair(<<,);
}
st[++top]=p;
}
}
std::sort(tree+,tree++all,cmp);
for (int i=;i<=all;i++){
int p=tree[i],f=father[p];
val[p]=son[p];
if (i>) In[p]=deep[p]-deep[f];
}
for (int i=all;i>;i--){
int p=tree[i],f=father[p];
near[f]=std::min(near[f],std::make_pair(near[p].first+In[p],near[p].second));
}
for (int i=;i<=all;i++){
int p=tree[i],f=father[p];
near[p]=std::min(near[p],std::make_pair(near[f].first+In[p],near[f].second));
}
for (int i=;i<=all;i++){
int p=tree[i],f=father[p],sum=son[find(p,deep[f]+)]-son[p];
if (f==) ans[near[p].second]+=n-son[p];
else{
val[f]-=sum+son[p];
if (near[p].second==near[f].second) ans[near[p].second]+=sum;
else{
int dis=(deep[p]-deep[f]-near[p].first+near[f].first)/;
if (dis+near[p].first==near[f].first+deep[p]-deep[f]-dis&&near[f].second<near[p].second) dis--;
int x=find(p,deep[p]-dis);
ans[near[p].second]+=son[x]-son[p];
ans[near[f].second]+=sum+son[p]-son[x];
}
}
}
for (int i=;i<=all;i++){
ans[near[tree[i]].second]+=val[tree[i]];
}
for (int i=;i<=m;i++)
printf("%d ",ans[tmp[i]]);
puts("");
}
int main(){
n=read();
bin[]=;
for (int i=;i<=;i++) bin[i]=bin[i-]*;
for (int i=;i<n;i++){
int x=read(),y=read();
add(x,y);
}
dfs();
int T=read();
while (T--) solve();
}

BZOJ 3572 世界树(虚树)的更多相关文章

  1. bzoj 3572世界树 虚树+dp

    题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...

  2. bzoj 3572 [Hnoi2014]世界树——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3572 关于虚树:https://www.cnblogs.com/zzqsblog/p/556 ...

  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

    https://www.lydsy.com/JudgeOnline/problem.php?id=3572 http://hzwer.com/6804.html 写的时候参考了hzwer的代码,不会写 ...

  5. bzoj 3572: [Hnoi2014]世界树 虚树

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

  6. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

  7. BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

    传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$ ...

  8. 【BZOJ】3572: [Hnoi2014]世界树 虚树+倍增

    [题意]给定n个点的树,m次询问,每次给定ki个特殊点,一个点会被最近的特殊点控制,询问每个特殊点控制多少点.n,m,Σki<=300000. [算法]虚树+倍增 [题解]★参考:thy_asd ...

  9. BZOJ 3572 世界树

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

随机推荐

  1. (转)Autotrace工具使用——小工具,大用场

    监控SQL语句,获取执行计划和执行成本,是每个Oracle开发人员与DBA所必须具备的能力之一. 当Oracle彻底进入CBO时代,我们面对一种全新的局面.一方面,基于数据统计量的CBO优化器,让SQ ...

  2. Is there a complete List of JVM exit codes

    Argument passed to System.exit(x) -> becomes the JVM exit code. Exit code 0 is used to indicate n ...

  3. hdu 4302 Holedox Eating

    http://acm.hdu.edu.cn/showproblem.php?pid=4302 #include <cstdio> #include <cstring> #inc ...

  4. 利用内存结构及多线程优化多图片下载(IOS篇)

    利用内存结构及多线程优化多图片下载(IOS篇) 前言 下载地址, 后续发布, 请继续关注本blog 在IOS中,我们常常遇到多图片下载的问题.最简单的解决方案是直接利用别人写好的框架.但是这如同练武, ...

  5. 杭州网赛 two rabbits (hdu 4745)

    算法很简单,问题是,怎么证明,答案是回文序列. 设a,b走的序列按顺时针是: a1 , a2 , a3 , ... , ak b1 , b2 , b3 , ... , bk 考虑端点的2种情况: 1. ...

  6. Hive 3、Hive 的安装配置(本地derby模式)

    这种方式是最简单的存储方式,只需要在hive-site.xml做如下配置便可; $ vim hive-site.xml <configuration>   <property> ...

  7. 《Java程序员面试笔试宝典》之switch使用时有哪些注意事项

    switch语句用于多分支选择,在使用switch(expr)的时候,expr只能是一个枚举常量(内部也是由整型或字符类型实现)或一个整数表达式,其中整数表达式可以是基本类型int或其对应的包装类In ...

  8. hdu 5433 Xiao Ming climbing(bfs+三维标记)

    Problem Description   Due to the curse made by the devil,Xiao Ming is stranded on a mountain and can ...

  9. Qt creator 搭配 valgrind 检测内存泄漏

    继上次重载operator new检测内存泄漏失败之后,妥协了.决定不管是否是准确指明哪一行代码出现内存泄漏,只要告诉我是否有泄漏就行了,这样就没有new替换的问题.在开发中,总是一个个小功能的开发. ...

  10. CharacterController 角色控制器实现移动和跳跃

    之前我使用SimpleMove来控制角色的移动, 后来又想实现人物的跳跃, 看见圣典里面是使用Move来实现的. =.= 然后我都把他们改成move来实现了 代码实现: using UnityEngi ...