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. ng-repeat 与ng-switch的简单应用

    效果如下图所示: 使用表格显示用户信息,当点击某条用户信息时,在其下方展开一行进行展示. index.html <!DOCTYPE html> <html ng-app=" ...

  2. 消息提醒,初探Notification

    1:MainActivity.java package com.example.notificationtest; import android.app.Activity; import androi ...

  3. cf B. Simple Molecules

    http://codeforces.com/contest/344/problem/B #include <cstdio> #include <cstring> using n ...

  4. Codeforces 486D D. Valid Sets

    http://codeforces.com/contest/486/problem/D 题意:给定一棵树,点上有权值,以及d,要求有多少种联通块满足最大值减最小值小于等于d. 思路:枚举i作为最大的点 ...

  5. 【转】android cts测试方法及步骤

    原文网址:http://blog.csdn.net/shi_xin/article/details/42262675 1.CTS下载 打开下面网址, http://source.android.com ...

  6. mysqli connect database and print

    <?php $connect = mysqli_connect('localhost','root','','intertrading') or die('Unale to connect'); ...

  7. HDU 5418 Victor and World (Floyd + 状态压缩DP)

    题目大意:从起点 1 开始走遍所有的点,回到起点 1 ,求出所走的最短长度. 思路:首先利用 Floyed 求出任意两点之间的最短距离 dis[i][j].求出任意两点之间的最短距离后,运用动态规划. ...

  8. Horner规则

    霍纳(Horner)规则是采用最少的乘法运算策略,求多项式 A(x) = a[n]x^n + a[n-1]x^(n-1) + ... + a[1]x^1 + a[0]x^0 在x处的值. 该规则为 A ...

  9. DBA 经典面试题(4)

    1.如果信息采集管理系统(ICM)崩溃了怎么办?  答案:所有其他的管理器都会继续工作.ICM只会处理队列控制请求,意思是开启和关闭其他并发的管理器.    2.你如何加速打补丁的过程?    答案: ...

  10. Android学习笔记__3__Android应用程序组成

    Android开发必须要了解构造块,Android应用程序是由里有六个重要组成部分组成的,这六种构造块如下:  ◆Activity ◆Intent Receiver ◆Service ◆Content ...