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

http://hzwer.com/6804.html 写的时候参考了hzwer的代码,不会写的题读一遍代码就好了(所以菜)。

虚树还是老一套,树形dp的部分比较有趣。

通过dfs两遍(从下往上总结一遍,从上往下再一遍)把每个点所归属的点找到。

对于那些没有出现在虚树中的点,对通过每条虚树上的边进行总结找到每两个点之间没有统计的点的归属(这个归属一定为bel[x]或bel[y])。

通过倍增中用lca找到距离判断来找每条边上分割点(可以发现需要找的是那种 bel[x] 和 bel[y] 在边两边的边, bel[x] 和 bel[y] 不在边两边时一定 bel[x] = bel[y] ),

那么对 bel[x] 的贡献为:siz[x在这条边上的第一个孩子] - siz[分割点] ,

对 bel[y] 的贡献为:siz[分割点] - siz[y] 。

还要注意一下那些作为某个虚树中的点的子树出现的点块,这些点是属于它的根(姑且这么说吧)的归属的,这部分贡献是在对边的统计结束后在统计虚树中每个点的归属时计算的。

说起来有点麻烦,读代码吧。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
using namespace std;
#define LL long long
const int maxn=;
int n,m,Q;
struct nod{
int y,next;
}e[maxn*];
int head[maxn]={},tot=;
int dep[maxn]={},id[maxn]={},siz[maxn]={},fa[maxn][]={},cnt=;
int a[maxn]={},bel[maxn]={},sta[maxn]={},tai=;
int c[maxn]={},re[maxn],tly=;
int f[maxn]={},b[maxn]={};
inline void init(int x,int y){e[++tot].y=y;e[tot].next=head[x];head[x]=tot;}
bool mcmp(int x,int y){
return id[x]<id[y];
}
void dfs(int x){
int y; siz[x]=; id[x]=++cnt;
for(int i=;i<=;i++)fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=e[i].next){
y=e[i].y; if(y==fa[x][])continue;
fa[y][]=x; dep[y]=dep[x]+; dfs(y);
siz[x]+=siz[y];
}
}
inline int getlca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=;i>=;--i)if(dep[fa[x][i]]>=dep[y])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][];
}
inline int getdis(int x,int y){
return dep[x]+dep[y]-*dep[getlca(x,y)];
}
void dfs1(int x){//get every points'bel[]
c[++tly]=x;re[x]=siz[x];
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
dfs1(y);if(bel[y]==)continue;
if(bel[x]==){bel[x]=bel[y];continue;}
int d1=getdis(bel[y],x),d2=getdis(bel[x],x);
if(d1<d2||(d1==d2&&bel[y]<bel[x]))bel[x]=bel[y];
}
}
void dfs2(int x){
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
if(bel[y]==)bel[y]=bel[x];
else{
int d1=getdis(bel[y],y),d2=getdis(bel[x],y);
if(d1>d2||(d1==d2&&bel[y]>bel[x]))bel[y]=bel[x];
}
dfs2(y);
}
}
void doit(int x,int y){
int son=y,mid=y;
for(int i=;i>=;--i)
if(dep[fa[son][i]]>dep[x])son=fa[son][i];
//cout<<x<<y<<son<<endl;
re[x]-=siz[son];
if(bel[x]==bel[y]){f[bel[x]]+=siz[son]-siz[y];return;}
for(int i=;i>=;--i){
int nxt=fa[mid][i];
if(dep[nxt]<dep[son])continue;
int d1=getdis(nxt,bel[x]),d2=getdis(nxt,bel[y]);
if(d1>d2||(d1==d2&&bel[y]<bel[x]))mid=nxt;
}
f[bel[x]]+=siz[son]-siz[mid];
f[bel[y]]+=siz[mid]-siz[y];
}
void solve(){
tot=;tly=;
scanf("%d",&m);
for(int i=;i<=m;i++){scanf("%d",&a[i]);b[i]=a[i];bel[a[i]]=a[i];}
sort(a+,a++m,mcmp);
if(a[]!=)sta[++tai]=;
sta[++tai]=a[];
for(int i=;i<=m;i++){
int lc=getlca(sta[tai],a[i]);
while(dep[sta[tai]]>dep[lc]){
if(dep[sta[tai-]]<=dep[lc]){init(lc,sta[tai]);--tai;break;}
init(sta[tai-],sta[tai]);tai--;
}
if(lc!=sta[tai])sta[++tai]=lc;
if(a[i]!=sta[tai])sta[++tai]=a[i];
}
while(--tai)init(sta[tai],sta[tai+]);
dfs1();dfs2();
for(int i=;i<=tly;i++){
for(int j=head[c[i]];j;j=e[j].next){
doit(c[i],e[j].y);
}
}
for(int i=;i<=tly;i++)f[bel[c[i]]]+=re[c[i]];
for(int i=;i<m;i++)printf("%d ",f[b[i]]);
printf("%d\n",f[b[m]]);
for(int i=;i<=tly;i++){head[c[i]]=;bel[c[i]]=;f[c[i]]=;re[c[i]]=;}
}
int main(){
//freopen("a.in","r",stdin);
scanf("%d",&n);
int x,y;
for(int i=;i<n;i++){scanf("%d%d",&x,&y);init(x,y);init(y,x);}
dep[]=;dfs();
scanf("%d",&Q);
memset(head,,sizeof(head));
for(int i=;i<=Q;i++)solve();
return ;
}

BZOJ 3572: [Hnoi2014]世界树 虚树 树形dp的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. 【BZOJ-3572】世界树 虚树 + 树形DP

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

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

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

  8. BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)

    题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...

  9. BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序

    https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...

随机推荐

  1. cdn_一些常用的cdn地址

    https://code.jquery.com/jquery-3.3.1.jshttps://cdn.bootcss.com/jquery/2.1.4/jquery.min.js https://cd ...

  2. 最长上升子序列O(nlogn) 要强的T^T(2358)

    题目来源:http://www.fjutacm.com/Problem.jsp?pid=2358 要强的T^T TimeLimit:1000MS  MemoryLimit:65536K 64-bit ...

  3. gradle 构建工具,与Ant Maven关系

    1   基本概念 gradle是一个基于Apache ant 和apache maven概念的项目自动化建构工具.它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的xml.当前其支持 ...

  4. 【codeforces】【比赛题解】#915 Educational CF Round 36

    虽然最近打了很多场CF,也涨了很多分,但是好久没写CF的题解了. 前几次刚刚紫名的CF,太伤感情了,一下子就掉下来了,不懂你们Div.1. 珂学的那场我只做了第一题……悲伤. 这次的Education ...

  5. Linux下MySQL/MariaDB Galera集群搭建过程【转】

    MariaDB介绍 MariaDB是开源社区维护的一个MySQL分支,由MySQL的创始人Michael Widenius主导开发,采用GPL授权许可证. MariaDB的目的是完全兼容MySQL,包 ...

  6. Django模型和ORM

    一.ORM ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是 ...

  7. URIEncoding与useBodyEncodingForURI 在tomcat中文乱码处理上的区别

    大家知道tomcat5.0开始,对网页的中文字符的post或者get,经常会出现乱码现象. 具体是因为Tomcat默认是按ISO-8859-1进行URL解码,ISO-8859-1并未包括中文字符,这样 ...

  8. 用Max导出Unity3D使用的FBX文件流程注解(转载)

    http://www.cnblogs.com/wantnon/p/4564522.html 从max导出FBX到Unity,以下环节需要特别注意.1,单位设置   很多人在建模,动画的时候,默认的ma ...

  9. 使用Scrapy命令行工具【导出JSON文件】时编码设置

    Windows 10家庭中文版,Python 3.6.4,virtualenv 16.0.0,Scrapy 1.5.0, 使用scrapy命令行工具建立了爬虫项目(startproject),并使用s ...

  10. linux tomcat 突然验证码出不来

    情况描述 虚拟机上用tomcat部署的web应用,本来都还可以的.后来打了一个快照进行过压缩后,重新起虚拟机发现应用登录界面的验证码出不来了,具体报的是500错误. 参见http://www.blog ...