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

关于虚树:https://www.cnblogs.com/zzqsblog/p/5560645.html

构造方法:

  先把关键点按 dfs 序排序,然后依次插入树中;

  插入当前点 cr 的时候,求 lca = get_lca( cr , sta[top] ) ;如果 dep[ sta[top] ] >= dep[lca] ,就一直弹栈;

  弹栈结束后,看看现在的 sta[ top ] 是不是就是 lca 了,如果不是,就 sta[ ++ top ] = lca ;同时 fa[ sta[top+1] ] = lca , fa[ lca ] = sta[ top ] ;

  把 cr 也加入栈中,即 sta[++top] = cr , fa[ cr ] = lca 。

sta[ 1 ] 就是虚树的根。

关于这道题:http://hzwer.com/6804.html

建好虚树,先换根 dp 得出虚树上的每个点应该被哪个点控制。换根的时候不用去掉该子树的贡献,因为不会有影响。

然后枚举虚树上的每条边 ( cr , fa ),用倍增在边上找到最浅的应该 “被控制 cr 的点控制” 的点 v ,然后 siz[v] - siz[cr] 和 siz[tv] - siz[v] 分别贡献即可,其中 tv 是 fa 在 v 方向的直接孩子。

关于不是虚树的点也不在虚树边上的那些点,自己的方法是在换根 dp 的时候处理;那个时候枚举孩子 v 的时候通过找 tv ,可以知道每个虚树上的点 cr 的不在虚树上的孩子们的 siz 和,直接贡献给控制 cr 的那个点即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define mkp make_pair
#define fir first
#define sec second
using namespace std;
int rdn()
{int ret=0;bool fx=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();return fx?ret:-ret;
}
const int N=3e5+5,K=18;
int n,hd[N],xnt,to[N<<1],nxt[N<<1];
int dfn[N],dep[N],pre[N][K+5],bin[K+5],lg[N],siz[N],sm[N];
pair<int,int> dp[N];
int m,ans[N],tt,sta[N],tot,fa[N],h2[N],xt2,t2[N<<1],nt2[N<<1];
struct Node{int v,id;}q[N];bool cmp(Node x,Node y){return dfn[x.v]<dfn[y.v];}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void ad2(int x,int y){t2[++xt2]=y;nt2[xt2]=h2[x];h2[x]=xt2;}
void ini_dfs(int cr,int fa)
{dfn[cr]=++tot; dep[cr]=dep[fa]+1;pre[cr][0]=fa; siz[cr]=1;for(int t=1,u;(u=pre[pre[cr][t-1]][t-1]);t++)pre[cr][t]=u;for(int i=hd[cr],v;i;i=nxt[i])if((v=to[i])!=fa){ini_dfs(v,cr); siz[cr]+=siz[v];}
}
int get_lca(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(int t=lg[dep[x]-dep[y]];t>=0;t--)if(dep[pre[x][t]]>=dep[y])x=pre[x][t];if(x==y)return x;for(int t=lg[dep[x]];t>=0;t--)if(pre[x][t]!=pre[y][t])x=pre[x][t],y=pre[y][t];return pre[x][0];
}
void build()
{sort(q+1,q+m+1,cmp); tt=m; tot=0;for(int i=1;i<=m;i++){int cr=q[i].v;if(!tot){sta[++tot]=cr;dp[cr]=mkp(0,cr);continue;}int lca=get_lca(cr,sta[tot]);while(dep[sta[tot]]>dep[lca])tot--;if(sta[tot]!=lca){q[++tt].v=lca; fa[sta[tot+1]]=lca;fa[lca]=sta[tot]; sta[++tot]=lca;dp[lca]=mkp(N,0);}fa[cr]=lca; sta[++tot]=cr; dp[cr]=mkp(0,cr);}for(int i=1;i<=tt;i++)if(fa[q[i].v])ad2(fa[q[i].v],q[i].v);
}
void dfs(int cr,int fa)
{for(int i=h2[cr],v;i;i=nt2[i])if((v=t2[i])!=fa){dfs(v,cr);int tp1=dp[v].fir+dep[v]-dep[cr],tp2=dp[cr].fir;if(tp1<tp2||(tp1==tp2&&dp[v].sec<dp[cr].sec))dp[cr].fir=tp1,dp[cr].sec=dp[v].sec;}
}
int fnd2(int cr,int fa)
{int d=dep[cr]-dep[fa]-1;while(d){int lbt=(d&-d);cr=pre[cr][lg[lbt]]; d-=lbt;}return cr;
}
void dfsx(int cr,int fa)
{int tp1=dp[fa].fir+dep[cr]-dep[fa],tp2=dp[cr].fir;if(fa&&(tp1<tp2||(tp1==tp2&&dp[fa].sec<dp[cr].sec)))dp[cr].fir=tp1,dp[cr].sec=dp[fa].sec;int s=siz[cr];for(int i=h2[cr],v;i;i=nt2[i])if((v=t2[i])!=fa){int tv=fnd2(v,cr);s-=siz[tv]; dfsx(v,cr);}sm[dp[cr].sec]+=s-1;//-1 for zj
}
int fnd(int cr,int fa)
{bool fg=(dp[cr].sec<dp[fa].sec);int x=dp[cr].fir,y=dp[fa].fir,d1=dep[cr],d2=dep[fa];for(int t=lg[dep[cr]-dep[fa]];t>=0;t--){int d=dep[pre[cr][t]];int u=d1-d+x,v=d-d2+y;if(u<v||(u==v&&fg))cr=pre[cr][t];}return cr;
}
bool In(int cr,int fa){return dfn[cr]>=dfn[fa]&&dfn[cr]<dfn[fa]+siz[fa];}
void solve()
{for(int i=1;i<=m;i++)sm[q[i].v]=0;int rt=sta[1]; dfs(rt,0); dfsx(rt,0);for(int i=1;i<=tt;i++)sm[dp[q[i].v].sec]++;for(int i=1;i<=tt;i++){int cr=q[i].v,f=fa[cr];if(!f) {sm[dp[cr].sec]+=n-siz[cr];continue;}int v=fnd(cr,f),tv=fnd2(cr,f);sm[dp[cr].sec]+=siz[v==f?tv:v]-siz[cr];//
      sm[dp[f].sec]+=siz[tv]-siz[v==f?tv:v];//tv//
    }for(int i=1;i<=m;i++)ans[q[i].id]=sm[q[i].v];for(int i=1;i<=m;i++)printf("%d ",ans[i]); puts("");
}
int main()
{n=rdn();for(int i=1,u,v;i<n;i++)u=rdn(),v=rdn(),add(u,v),add(v,u);bin[0]=1;for(int i=1;i<=K;i++)bin[i]=bin[i-1]<<1;for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;ini_dfs(1,0); int Q=rdn();while(Q--){for(int i=1;i<=tt;i++)h2[q[i].v]=0; xt2=0;for(int i=1;i<=tt;i++)fa[q[i].v]=0;///
      m=rdn(); for(int i=1;i<=m;i++)q[i].v=rdn(),q[i].id=i;build(); solve();}return 0;
}

转载于:https://www.cnblogs.com/Narh/p/10367190.html

bzoj 3572 [Hnoi2014]世界树——虚树相关推荐

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

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

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

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

  3. bzoj 3572: [Hnoi2014]世界树

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

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

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

  5. bzoj3572世界树 虚树+树型动规

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 1786   Solved: 957 [ Submit][ ...

  6. 「HNOI2014」世界树 虚树

    「HNOI2014」世界树 前置技能:虚树. (本题可以通过以下相似的思想用线段树维护子树信息和倍增找中点完成,代码短很多,但本篇题解不涉及) 题解部分 这种总询问点数不大,但是询问次数多,可以想到用 ...

  7. luogu3233 世界树 (虚树)

    反正肯定要建虚树,考虑建完之后怎么做 先随便dp一下算出来距离某点最近的询问点mi[x](因为有的虚树上的点它不是询问点嘛) 那我们对于某条链x到fa[x]上的非虚树上的点(包括他们的非虚树上的孩子) ...

  8. BZOJ 3611 [Heoi2014]:虚树+树形DP

    时空隧道 今天考试T3正解是虚树-..(看到这个名字我好虚啊-.) 现在我们需要处理一棵树上k个点的询问,做一遍树形DP-- 复杂度是O(n)的,q个询问,感觉复杂度很爆炸-..>_<-- ...

  9. BZOJ3572: [Hnoi2014]世界树

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

最新文章

  1. Mac Pro 开机自启动 PHP-FPM,Nginx,MySql 等软件
  2. r语言 整理、处理数据步骤_R语言万能数据清洗整理包Tidyverse(一)
  3. arcgis数据文件使用
  4. Zuhair and Strings
  5. C++11新特性学习
  6. rest和rest ful_为什么REST如此重要
  7. 最详细的Fast RCNN论文笔记
  8. SPendidCRM:给HK的ImageInfoEntryEditView增加一个checkbox,用于判断特殊类型的PODS记录...
  9. Android Makefile and build system 分析
  10. 学好python浪漫表白,表白代码
  11. 解决git文件夹图标消失
  12. linux 6.5光驱是什么意思,linux 6和5有什么不同
  13. python pandas dataframe 不显示索引_Python DataFrame 设置输出不显示index(索引)值的方法...
  14. html+复制插件,jenkins 插件Copy Artifacts + Artifacts to copy
  15. FANUC机器人_三点法设置工具坐标系的具体方法步骤(图文)
  16. Android开发——获取并生成唯一识别码
  17. css调整标签内背景图片的大小和位置
  18. 经典:uC/OS-II系统的学习教程之(2)
  19. 康宁玻璃ct值计算公式_CT值的计算公式?
  20. Fortran:实现矩阵直积

热门文章

  1. os模块中的shutil的使用方式与方法
  2. jsp 中forward 和 Redirect 的用法区别
  3. 逆序输出(数组练习)
  4. 鸡兔同笼 n为总数,m为总腿数,a为鸡,b为兔
  5. dokuwiki 的管理和使用(补充)
  6. 使用java命令运行class文件提示“错误:找不到或无法加载主类“的问题分析
  7. 一文看懂Python(一)-----列表和元组篇
  8. C语言再学习 -- Ubuntu 12.04 root用户登录设置
  9. 嵌入式文件系统镜像制作及烧写
  10. Ubuntu断电重启后黑屏左上角光标闪烁,分辨率低解决办法