题目大意

有一棵有n个点的树,给出q组询问,每组询问有 mi m_i点,称之为关键点,每组点的个数和(即 ∑q1mi \sum_1^qm_i)与n同阶,每个树上的点被与其距离最近的关键点控制,求每个关键点控制了多少个点。

虚树

希望我能写出通俗易懂的东西来让读者理解
虚树就是只与关键点有关的树,一个点被置于虚树中当且仅当该点为关键点或该点为某两个关键点的公共祖先(纯属个人理解,如有疑问可评论或私信),那么按照这个定义我们建树的方法是需要 O(n2) O(n^2)的,所以我们需要一个可行的建树方法。
我们可以发现其实很多点都是重复的,那么我们可以转化一下定义,一个点被置于虚树中当且仅当该点为关键点或他的两个儿子的子树中存在关键点。
那么可以得到一个可行的方法:我们将所有关键点先按dfs序排序,然后开一个栈,表示当前点在原树中到根的路径上在虚树上的点,我们考虑从左到右加点,假设当前加入的点为x,x与当前栈顶的公共祖先为y,那么很明显,加入x后,原栈内深度大于y的点都会被踢出,而被删掉的点之间其实就对应了虚树中的连边,也就是说我们可以在点退栈时连边。
于是就建出一棵虚树。
举个例子(红点即为关键点)

为方便,图中点的编号即为其dfs序。
那么我们先加入3
此时栈为(3)
我们考虑加入5
那么3和5的lca为2
现在弹出栈内元素,因为3的深度大于2,那么弹出3,在虚树中2与3连边,栈为()
加入2,此时栈为(2),再加入5,此时栈为(2,5)。
考虑加入6
那么5和6的lca为2
考虑弹出栈内元素,因为5的深度大于2,那么弹出5,在虚树中2与5连边,栈为(2)
考虑加入2,因为栈顶为2所以不用加入,考虑加入6,此时栈为(2,6)
最后处理栈内元素,在虚树中2与6连边
最后得到虚树:

详情可以看标程

回到本题

那么得出虚树后,我们就可以进行树形DP,先对于每个点求出其最近的关键点,然后对于一条虚树上的边,我们可以寻找分界点,然后计算答案

贴个代码:

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;
typedef double db;const int N = 300010;struct edge{int x,next;
}e[N*3];
int tot,h[N*2],qt,vis[N],tim;
int n,m,q;
int fa[N][20];
int dfn[N],k,s[N],dep[N];
int a[N],sta[N],top,he[N],bz[N],f[N],v[N],ff[N];
db up;
int mi[21];
int ans[N];int get(){char ch;int s=0;while(ch=getchar(),ch<'0'||ch>'9');s=ch-'0';while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';return s;
}void inse(int x,int y){e[++tot].x=y;e[tot].next=h[x];h[x]=tot;
}void dfs(int x){s[x]=1;dfn[x]=++k;fo(i,1,up)fa[x][i]=fa[fa[x][i-1]][i-1];for(int p=h[x];p;p=e[p].next)if (!s[e[p].x]){fa[e[p].x][0]=x;dep[e[p].x]=dep[x]+1;dfs(e[p].x);s[x]+=s[e[p].x];}
}bool cmp(int x,int y){return dfn[x]<dfn[y];
}void updata(int x){if (vis[x]<tim){vis[x]=tim;h[x+n]=0;}
}void dfs1(int x){f[x]=v[x]=0;if (bz[x]==tim)f[x]=x;for(int p=h[x+n];p;p=e[p].next)if (e[p].x-n!=ff[x]){int y=e[p].x-n;dfs1(y);if (!f[x]||(f[y]&&(v[x]>dep[f[y]]-dep[x]||(v[x]==dep[f[y]]-dep[x]&&f[y]<f[x])))){f[x]=f[y];v[x]=dep[f[y]]-dep[x];}}
}int jump(int x,int len){fd(i,up,0)if (len>=mi[i]){x=fa[x][i];len-=mi[i];}return x;
}void add(int fy,int y,int fx,int x){int len=dep[y]-dep[x];if (len%2){int ty=jump(y,len/2);ans[fy]+=s[ty]-s[y];ans[fx]+=s[jump(y,len-1)]-s[ty];}else{int ty=jump(y,len/2-1);ans[fy]+=s[ty]-s[y];ans[fx]+=s[jump(y,len-1)]-s[fa[ty][0]];if (fx<fy)ans[fx]+=s[fa[ty][0]]-s[ty];else ans[fy]+=s[fa[ty][0]]-s[ty];}
}void dfs2(int x){ans[f[x]]+=s[x];int tx=x;for(int p=h[x+n];p;p=e[p].next)if (e[p].x-n!=ff[x]){int y=e[p].x-n;if (!f[y]||(v[y]>v[x]+dep[y]-dep[x]||(v[y]==v[x]+dep[y]-dep[x]&&f[x]<f[y]))){f[y]=f[x];v[y]=v[x]+dep[y]-dep[x];}int ty=jump(y,dep[y]-dep[x]-1),fx=f[x],fy=f[y];ans[f[x]]-=s[ty];if (fx==fy)ans[fx]+=s[ty]-s[y];elseif (v[y]<v[x]){if (dep[y]-dep[x]==v[x]-v[y])ans[fy]+=s[ty]-s[y];else{ans[fy]-=s[y];y=jump(y,v[x]-v[y]);ans[fy]+=s[y];add(fy,y,fx,x);}}else if (v[y]>=v[x]){if (dep[y]-dep[x]==v[y]-v[x])ans[fx]+=s[ty]-s[y];else{ans[fx]+=s[ty];x=jump(y,dep[y]-dep[x]-v[y]+v[x]-1);ans[fx]-=s[x];x=fa[x][0];add(fy,y,fx,x);}}x=tx;dfs2(e[p].x-n);}
}int getfather(int x,int y){if (dep[x]<dep[y])swap(x,y);fd(i,up,0)if (dep[fa[x][i]]>=dep[y])x=fa[x][i];if (x==y)return x;fd(i,up,0)if (fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];return fa[x][0];
}void solve(){m=get();tim++;//---------------------------------------------------------fo(i,1,m){ans[a[i]=he[i]=get()]=0;bz[a[i]]=tim;}sort(a+1,a+1+m,cmp);sta[top=1]=a[1];tot=qt;updata(a[1]);int root;fo(i,2,m){int x=a[i];int tf=getfather(x,sta[top]);updata(x),updata(tf);while(top&&dep[sta[top]]>dep[tf]){if (top>1&&dep[sta[top-1]]>dep[tf])inse(sta[top-1]+n,sta[top]+n);else inse(tf+n,sta[top]+n);top--;}if (!top||dep[sta[top]]<dep[tf])sta[++top]=tf;if (!top||dep[sta[top]]<dep[x])sta[++top]=x;}while(top){if (top>1)inse(sta[top-1]+n,sta[top]+n);top--;}
//-----------------------------以上为建虚树--------------------------int delta=s[root];s[root]=n;ff[root]=0;dfs1(root);dfs2(root);s[root]=delta;fo(i,1,m)printf("%d ",ans[he[i]]);putchar('\n');
}int main(){freopen("worldtree.in","r",stdin);freopen("worldtree.out","w",stdout);n=get();mi[0]=1;fo(i,1,20)mi[i]=mi[i-1]*2;fo(i,1,n-1){int x=get(),y=get();inse(x,y);inse(y,x);}qt=tot;up=log(n)/log(2);dfs(dep[1]=1);q=get();fo(i,1,q)solve();fclose(stdin);fclose(stdout);return 0;
}

【HNOI2014】世界树相关推荐

  1. BZOJ3572: [Hnoi2014]世界树

    题解: 首先建出一颗虚树  对于虚树上的每个节点DP找出离得最近的关键节点的编号和距离 然后考虑一遍dfs 对于每条链上子树 我们倍增找到mid位置 然后mid以下的属于下面节点 mid以上的属于上面 ...

  2. 虚树(bzoj 3572: [Hnoi2014]世界树)

    例题: 一棵n个节点的树,m次查询,每次查询给你一个点集U,对于树上的所有节点x(x∉U),你要找到一个点y(y∈U)满足y点离x点最近且标号最小,表示x点受y点管辖,而你的任务就是对于每次查询输出U ...

  3. BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

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

  4. [HNOI2014]世界树 (虚树DP+倍增)

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

  5. [bzoj3572][HNOI2014]世界树

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

  6. bzoj 3572: [Hnoi2014]世界树

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

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

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

  8. bzoj3572 [HNOI2014]世界树 虚树 +乱dp

    这个题有Σ的条件,肯定还是用log结构求询问点相关了 但这个题是点之间的距离关系,所以本来想用中点来代替原来的lca,但中点的个数不满足任何单调性,而且个数也不是n个 所以还是要用lca,所以考虑lc ...

  9. BZOJ3572 [HNOI2014]世界树

    Address BZOJ3572 洛谷P3233 Solution 先建出虚树. 记 id[x] i d [ x ] id[x] 表示距离点 x x x 最近的关键点编号,dis[x]" r ...

  10. [BZOJ3572] [Hnoi2014]世界树

    传送门 http://www.lydsy.com/JudgeOnline/problem.php?id=3572 题目大意 给定一棵树,每次给一些关键点,树上每个点都被离他最近的关键点支配,距离相同取 ...

最新文章

  1. Java的多态(详尽版)
  2. classpath: spring 中的查找方式
  3. java判断有没有修改,java字节码判断对象应用是否被修改
  4. 美团自研无人机登场:15分钟配送到家
  5. 晨哥真有料丨生而为人,你讨好世界的样子真的很丑!(讨好型人格)
  6. 随想录(用好Visual Studio开发平台)
  7. 新版犀牛书该不该入手?
  8. 美瞳微商如何引流?微商卖美瞳怎么宣传?美瞳微商如何引流人脉
  9. AI智能识别盒 智能识别垃圾分类
  10. SpringBoot使用Nacos作为配置中心服务和服务注册中心
  11. ad网络标号怎么用_altium designer网络标号的作用范围
  12. Python下载qq音乐歌曲实例教程
  13. sundayplayer第一版本开放源代码
  14. 通过MatLab将传递函数离散化
  15. (转)(图文详细)win 10禁用F1到F12热键/win10 把F1到F12多媒体键转变为功能键
  16. package-info类
  17. android 开源库osmdroid绘制点线面(比例尺,缩小放大,导航图标等)
  18. 毕业两年的混社会经验:给应届生朋友们的建议【含求职经验】
  19. Struts 2 in Action 中文版出版了!
  20. IDEA new project

热门文章

  1. errpt DCB47997
  2. 山地果园管道自动喷雾系统设计与试验
  3. C语言 strcpy_s 函数 - C语言零基础入门教程
  4. 源代码jQuery简单数学计算器Web页面html
  5. 解决Windows不能显示隐藏文件的问题
  6. 计算机平面设计专业技能怎么填,计算机平面设计专业毕业生情况调查问卷
  7. 交易机制(2007 范建军)
  8. css可以修改超链接颜色吗?
  9. 深入浅出系列之——KMP算法详解【吐血整理】
  10. UOJ Test Round 1