题目大意

有一棵有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. 有哪些适合远程办公的软件值得推荐?
  2. eclipse可以写前端吗_Python 竟然也可以写网页前端了!
  3. Spring MVC Controller 要点
  4. 【单调栈】Largest Rectangle in a Histogram(luogu-SP1805/poj 2559)
  5. 【转】C#搭建Oauth2.0认证流程以及代码示例
  6. 漫步线性代数十三——线性变换
  7. Java基础学习总结(121)——Java JVM执行流程
  8. SQL Server 轻松解决令你头疼的sa登录
  9. android渐变效果
  10. VMware下CentOS安裝完後認唔到網卡
  11. 一个vue项目同时兼容pc和移动端
  12. FAT文件系统介绍以及FatFs的移植
  13. arduino 嗡鸣器 音乐_arduino笔记一:用arduino实现蜂鸣器播放音乐
  14. Windows Server 2008 简体中文 正式版 下载
  15. 适用于编程开发自学的学习网站
  16. Holm–Bonferroni method
  17. 【SPSS】交叉设计方差分析和协方差分析详细操作教程(附案例实战)
  18. html5 单页动画,超炫的动画效果单页网站
  19. 关于Angular 4 + ng-zorro 使用过程中遇到的问题
  20. steam插件_教程丨如何查询Steam游戏的历史价格信息

热门文章

  1. Chrome Emulated Devices Add iPhone XS Max
  2. 解决民生九难,城投隆翔助力西安停车产业发展
  3. Java实习生在公司里一般都做什么事情?
  4. Hadoop+Hbase+Springboot实现企业能源消耗监测大数据分析系统
  5. 《穷爸爸富爸爸》 —— 罗伯特访问记录
  6. 女人心疼男人的10种方式 太经典了!!
  7. 什么是KMP算法(详解)
  8. 最新!!Android 状态栏详细开发,5分钟精通状态栏
  9. 从点云到网格(三)Poisson重建(转)
  10. Linux系统移植流程