正题

题目链接:https://www.luogu.com.cn/problem/P3233


题目大意

nnn个点的一棵树,mmm次选出一些点作为关键点。每个树上的点会对最近的关键点做贡献,求每个关键点的贡献。


解题思路

显然是虚树,考虑如何在虚树上求贡献,我们发现难处理的是虚树上每一条链的贡献,因为这个链上代表了原树上的多个点。我们可以先对于虚树上每一个点求出一个nerxner_xnerx​表示距离它最近的关键点。

然后我们对于一条边,我们可以计算出一个长度表示该边代表的链这个长度一下都是属于yyy的,上面的属于xxx的。然后我们可以倍增求出原树上的分界点来计算答案。

因为建虚树和求答案的logloglog是分开来的,所以时间复杂度为O((n+∑k)log⁡n)O(\ (n+\sum k)\ \log n)O( (n+∑k) logn)


codecodecode

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=300100,T=20;
struct node{int to,next;
}a[N*2];
int n,q,k,tot,cnt,ls[N],siz[N],dep[N],dfn[N];
int ner[N],ans[N],p[N],pos[N],s[N],f[N][T+1];
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
bool cMp(int x,int y){return pos[x]<pos[y];}
int LCA(int x,int y){if(dep[x]>dep[y])swap(x,y);for(int i=T;i>=0;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i];if(x==y)return x;for(int i=T;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];return f[x][0];
}
int gup(int x,int k){for(int i=T;i>=0;i--)if((k>>i)&1)x=f[x][i];return x;
}
void Add(int x){if(!cnt){s[++cnt]=x;return;}int lca=LCA(x,s[cnt]);while(cnt>1&&dep[s[cnt-1]]>dep[lca])addl(s[cnt-1],s[cnt]),cnt--;if(dep[s[cnt]]>dep[lca])addl(lca,s[cnt]),cnt--;if((!cnt)||(s[cnt]!=lca))s[++cnt]=lca;s[++cnt]=x;return;
}
void dfs1(int x,int fa){siz[x]=1;dep[x]=dep[fa]+1;dfn[x]=++cnt;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;f[y][0]=x;dfs1(y,x);siz[x]+=siz[y];}return;
}
int get_dis(int x,int y)
{return dep[x]+dep[y]-2*dep[LCA(x,y)];}
void dfs_son(int x,int fa){if(pos[x])ner[x]=x;else ner[x]=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to,w=dep[y]-dep[x];if(y==fa)continue;dfs_son(y,x);if(!ner[x]||dep[ner[y]]<dep[ner[x]]||(dep[ner[y]]==dep[ner[x]]&&ner[y]<ner[x]))ner[x]=ner[y];}return;
}
void dfs_father(int x,int fa){for(int i=ls[x];i;i=a[i].next){int y=a[i].to,w=dep[y]-dep[x];if(y==fa)continue;int zx=get_dis(x,ner[x]),zy=get_dis(y,ner[y]);if(!ner[y]||zy>zx+w||(zy==zx+w&&ner[x]<ner[y]))ner[y]=ner[x]; dfs_father(y,x);}return;
}
void solve(int x,int fa){ans[ner[x]]+=siz[x]; for(int i=ls[x];i;i=a[i].next){int y=a[i].to,w=dep[y]-dep[x]-1,gd=gup(y,w);if(y==fa)continue;if(ner[x]==ner[y])ans[ner[x]]+=siz[gd]-siz[y];else{int zx=get_dis(x,ner[x]),zy=get_dis(y,ner[y]);int k=(zx+zy+w)/2;if((zx+zy+w)&1)k+=ner[y]<ner[x];k-=zy;int pw=gup(y,k);if(k<=0)ans[ner[x]]+=siz[gd]-siz[y];else if(k>w)ans[ner[y]]+=siz[gd]-siz[y];else ans[ner[y]]+=siz[pw]-siz[y],ans[ner[x]]+=siz[gd]-siz[pw];}ans[ner[x]]-=siz[gd];solve(y,x);}ls[x]=0;return;
}
int main()
{scanf("%d",&n);for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}dfs1(1,1);for(int j=1;j<=T;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];memset(ls,0,sizeof(ls));scanf("%d",&q);while(q--){scanf("%d",&k);tot=cnt=0;for(int i=1;i<=k;i++)scanf("%d",&p[i]),pos[p[i]]=i;sort(p+1,p+1+k,cmp);if(p[1]!=1)s[++cnt]=1;for(int i=1;i<=k;i++)Add(p[i]);while(cnt>1)addl(s[cnt-1],s[cnt]),cnt--;dfs_son(1,1);dfs_father(1,1);solve(1,1);sort(p+1,p+1+k,cMp);for(int i=1;i<=k;i++)printf("%d ",ans[p[i]]),ans[p[i]]=pos[p[i]]=0;putchar('\n');}return 0;
}

P3233-[HNOI2014]世界树【虚树,倍增】相关推荐

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

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

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

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

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

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

  4. 「HNOI2014」世界树 虚树

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

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

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

  6. luogu3233 世界树 (虚树)

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

  7. UOJ#271. 【清华集训2016】连通子树(虚树+倍增)

    传送门 题解: 注意到每种颜色个数比较少,于是建出虚树后暴力背包,用倍增维护一下虚链上的DP值即可. 所以说你只需要5个倍增数组和一些卡常技巧加上无数的小细节就可以通过这道题了. 不说了我去睡觉了. ...

  8. 虚树 virtual-tree

    我们发现,如果一棵树中真正需要处理的点很少,而总共点数很多时,可以只处理那些需要的点,而忽略其他点. 因此我们可以根据那些需要的点构建虚树,只保留关键点. oi-wiki上对虚树的介绍 我们根据一下方 ...

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

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

最新文章

  1. 一次使用Eclipse Memory Analyzer分析weblogic内存溢出
  2. linux ssh -R 代理不同内网主机互连
  3. 【markdown】图片的处理
  4. android 蓝牙 setscanmode,蓝牙LE扫描在后台无法在Android M上运行
  5. 这家工作室花三年把塞尔达做进RogueLike里面
  6. 第一次参加数学建模竞赛如何夺取一等奖
  7. PaddlePaddle顶会论文复现 | ECO视频动作识别网络
  8. (二)设置hexo支持mermaid
  9. java的robot_Java中的Robot不执行命令
  10. python代替mathematica_在 Mathematica 里与 Python 交互
  11. 通信学会学术年会感受
  12. 【Windows】合并分区教程(解决C盘空间不足)
  13. 人声歌姬语音合成器+全套拓展 – Yamaha Vocaloid 4.3.0 + ALL Libraries WiN
  14. 空间两直线间最短距离计算公式
  15. 数字IC后端真的不如前端设计和验证吗?
  16. C/C++ 使用信号量控制线程运行顺序
  17. 免费把pdf转换成excel
  18. MySQL数据类型之数值型
  19. Android简易项目SQLite的简单运用——简易记事本
  20. sql 统计常用的sql

热门文章

  1. 6计算机系统的组成是,计算机系统的组成(范文)(6页)-原创力文档
  2. 因子分析最少要有几个因子_Re0:魔女司教和魔女是什么关系?他们的魔女因子是魔女给的吗...
  3. 配置yml_dctc:生成docker-compose.yml配置的工具
  4. c++歌手大赛系统_计人即讯|第十届程序设计大赛
  5. java接口课程_用java定义一个接口,用于查询课程
  6. php按时间分组的sql语句,(SQL语句)按指定时间段分组统计
  7. yii 使用 有赞sdk_有赞ABTest系统:数据驱动增长实践
  8. PHP秒杀截流原理,节流阀和去抖动的基本实现方法介绍
  9. python3的float数精度_python浮点数精度问题
  10. [JavaWeb-Bootstrap]Bootstrap快速入门