洛谷P3233 世界树 [HNOI2014] 虚树
正解:虚树
解题报告:
传送门!
首先看到这种就要想到虚树这个是毫无疑问的QwQ
建虚树什么的都可以循规蹈矩地做,不说辣,具体可以看下虚树学习笔记什么的看下板子
但是建好虚树之后怎么搞还是有点儿讲究,所以专门开个题解港下(所以为什么好多人拿这个当做虚树入门题什么的昂,,,大概我太菜辣所以只有理解了半天趴QAQ(我我我我在网上找题解看到好多都是说,"首先求值很容易balabala",,,就很绝望,,,可能真的我太菜辣QAQ
首先读入dfs然后建虚树什么的跳过,直接到计算答案的地方
这里主要分为两大部分,分别港下w
(然后为了表述方便,先define一下,x的被管辖点y指y管x
首先找到虚树上每个节点的被管辖点(编号&距离
考虑到虚树上的点有两个情况,第一个是管辖点,显然属于自己,不说
然后如果不是管辖点,考虑到一定要么在子树中,要么不在子树中(...好废话啊)
如果在子树中,可以递归下去更新就好
如果不在子树中,考虑到管辖点和它的路径一定通过与父亲节点的连边,所以可以通过父亲节点的最近点更新
但是考虑到如果我们在做dfs的时候是先枚举儿子节点再计算这个点的结果的(实现算出管辖点在子树中的情况w
所以在做点x的时候实际上x的父亲的结果是还麻油求出来的
所以再另外dfs一遍就好了
然后关于这个还有另外一种理解方法,实现是一样的但是我还是大概港下QAQ
就是任意一条路径必然是向上走几步(也可以不走)再向下走几步
所以可以分别求出来向上向下,也就是我上面说的分别求出子树中和通过父亲节点w
(一个小技巧是由题意可得这个信息是以距离为第一关键字编号为第二关键字,所以用pair就很susi!
(虽然这个小技巧挺显然的我不说应该也能知道QAQ
upd:
打完代码之后发现有个之前麻油注意到的点,,,就是因为我们后面都是用的size昂这种的,就都是算的它子树里面的,然后如果有一个情况,给定的点都在最初dfs的根节点的一侧,那么另一侧的点就都统计不到辣(这个样例给得挺给力的,我就是测样例的时候发现的这个问题w
所以解决方法是在建虚树的时候直接强制性给它加入1号节点(就是最初dfs的根结点,因为我习惯直接从1号节点开始所以我是直接加1号
然后因为我是打完了代码才发现的这个问题,就不想对虚树进行大改了,所以就直接在原来的基础上判断一下有麻油1号,麻油直接强制加入就好,然后输出的时候注意特判一下不要输出多了/少了就好QwQ
il void dfs_fk_dtu(ll x)
{
if(ext[x])bl[x]=mp(,x);else bl[x]=mp(inf,);
e_fk(i,x){dfs_fk_dtu(t_fk(i));bl[x]=min(bl[x],mp(bl[t_fk(i)].fr+dep[t_fk(i)]-dep[x],bl[t_fk(i)].sc));}
}
il void dfs_fk_utd(ll x,ll dis,ll nm){if(bl[x]>mp(dis,nm))bl[x]=mp(dis,nm);e_fk(i,x)dfs_fk_utd(t_fk(i),bl[x].fr+dep[t_fk(i)]-dep[x],bl[x].sc);}这儿是代码w
然后计算每个管辖点管了多少个节点
现在考虑虚树上的点x,它的被管辖点是y,然后现在考虑它在实树上的儿子节点z,然后就花式分类讨论昂
可以想到如果z的子树中麻油管辖点,那么整棵z的被管辖点都是y,就可以ans+=size[z]
然后如果有管辖点,就比较难算,可以先当做整棵z的被管辖点都不是y,之后再把是y的加上,等下另说
那么实现就是直接在虚树上做,对虚树上的点x,首先被管辖点y的ans是+=size[x]的,然后枚举它在虚树上的儿子节点z,对所有儿子节点倍增跳到实树上的x节点的儿子节点(x-y那条链上的儿子节点昂
这时候考虑到我们把含有z的整棵子树都减辣,显然是不对的,反例都懒得举辣太显然辣,,,
所以就把减多了的加上来就好
所以就枚虚树上的边,对于边两侧的两点,如果他们的被管辖点是一样的,那在前面的计算中相当于减了又加了,不管
如果不一样,它们两个之间的点就都麻油被计入答案中
这里随便解释一下趴还是比较显然的,,,?
令这条边两侧的点是x和y,且x是y的父亲
那么y中的节点肯定在第一步中给y的被管辖点提供贡献辣(如果y中又有关键点什么的不要在意!当做解决辣就是!子问题而已!)
x子树中除了y的所有节点肯定在第一步中给x的被管辖点提供答案辣(x中有其他关键点也同上括号
综上,就只会有x到y之间的点麻油计入答案辣
所以就倍增跳啊跳地算出来就可以辣
最后说一下,,,看起来这儿又是要两次dfs的,其实显然一次就足够,所以我打的是一次dfs的w
il void dfs_cal(ll x)
{
ll siz=sz[x];
e_fk(i,x)
{
ll sn=chd(t_fk(i),x);dfs_cal(t_fk(i));
siz-=sz[sn];
if(bl[t_fk(i)]==bl[x])siz+=sz[sn]-sz[t_fk(i)];
else
{
ll tmp=t_fk(i);
my(j,,)
if(mp(dep[t_fk(i)]-dep[fa[tmp][j]]+bl[t_fk(i)].fr,bl[t_fk(i)].sc)<mp(dep[fa[tmp][j]]-dep[x]+bl[x].fr,bl[x].sc))tmp=fa[tmp][j];
as[bl[t_fk(i)].sc]+=sz[tmp]-sz[t_fk(i)];siz+=sz[sn]-sz[tmp];
}
bl[t_fk(i)]=mp(inf,);
}
as[bl[x].sc]+=siz;
head_fk[x]=;
}不建议直接复制粘贴,因为这个思想挺好的,还是自己打一下加深理解为好QAQ而且也麻油很多,自己好好理解然后打出来成就感还是max的呢!
综上,这道题就做完辣,最后只要把最初的构建虚树之类的代码和上面两个代码拼接起来就打完正解辣!
代码可能有点丑陋(压行+一堆宏定义+丑陋命名,我自己都有点嫌弃,,,我错了下次还敢TT
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define rg register
#define ll long long
#define fr first
#define sc second
#define gc getchar()
#define mp make_pair
#define t_rl(i) edge_rl[i].to
#define t_fk(i) edge_fk[i].to
#define w_rl(i) edge_rl[i].wei
#define w_fk(i) edge_fk[i].wei
#define rp(i,x,y) for(rg ll i=x;i<=y;++i)
#define my(i,x,y) for(rg ll i=x;i>=y;--i)
#define e_rl(i,x) for(rg ll i=head_rl[x];i;i=edge_rl[i].nxt)
#define e_fk(i,x) for(rg ll i=head_fk[x];i;i=edge_fk[i].nxt) const ll N=+,M=+,inf=1e12;
ll edge_rl_cnt,edge_fk_cnt,head_rl[N],head_fk[M],dep[N],fa[M][],n,m,ld_cnt,land[M],cnt_dfn,dfn[N],stck[N],head_stck,output[M],rt,as[N],sz[N];
bool ext[M];
pair<ll,ll>bl[N];
struct ed{ll to,nxt,wei;}edge_rl[N<<],edge_fk[M]; il ll read()
{
rg char ch=gc;rg ll x=;rg bool y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il void ad_rl(rg ll x,rg ll y,rg ll z){edge_rl[++edge_rl_cnt]=(ed){y,head_rl[x],z};head_rl[x]=edge_rl_cnt;}
il void ad_fk(rg ll x,rg ll y,rg ll z){edge_fk[++edge_fk_cnt]=(ed){y,head_fk[x],z};head_fk[x]=edge_fk_cnt;}
void dfs_rl(ll nw,ll fat)
{
dfn[nw]=++cnt_dfn;
dep[nw]=dep[fat]+;sz[nw]=;fa[nw][]=fat;rp(i,,)fa[nw][i]=fa[fa[nw][i-]][i-];
e_rl(i,nw)if(t_rl(i)^fat)dfs_rl(t_rl(i),nw),sz[nw]+=sz[t_rl(i)];
}
il bool cmp(ll gd,ll gs){return dfn[gd]<dfn[gs];}
il ll lca(ll x,ll y)
{
if(dep[x]<dep[y])swap(x,y);
my(i,,)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
my(i,,)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][];
}
il ll chd(ll x,ll y){my(i,,)if(dep[fa[x][i]]>dep[y])x=fa[x][i];return x;}
il void build_fk()
{
head_stck=edge_fk_cnt=;
sort(land+,land++ld_cnt,cmp);
rp(i,,ld_cnt)
{
if(!head_stck)stck[++head_stck]=land[i];
else
{
ll grd=lca(stck[head_stck],land[i]);
if(grd==stck[head_stck]){stck[++head_stck]=land[i];continue;}
while(dep[stck[head_stck-]]>dep[grd])
ad_fk(stck[head_stck-],stck[head_stck],dep[stck[head_stck-]]-dep[stck[head_stck]]),--head_stck;
if(grd!=stck[head_stck-])ad_fk(grd,stck[head_stck],dep[grd]-dep[stck[head_stck]]),stck[head_stck]=grd,stck[++head_stck]=land[i];
else ad_fk(grd,stck[head_stck],dep[grd]-dep[stck[head_stck]]),stck[head_stck]=land[i];
}
}
while(head_stck>)ad_fk(stck[head_stck-],stck[head_stck],dep[stck[head_stck-]]-dep[stck[head_stck]]),--head_stck;rt=stck[head_stck];
}
il void dfs_fk_dtu(ll x)
{
if(ext[x])bl[x]=mp(,x);else bl[x]=mp(inf,);
e_fk(i,x){dfs_fk_dtu(t_fk(i));bl[x]=min(bl[x],mp(bl[t_fk(i)].fr+dep[t_fk(i)]-dep[x],bl[t_fk(i)].sc));}
}
il void dfs_fk_utd(ll x,ll dis,ll nm){if(bl[x]>mp(dis,nm))bl[x]=mp(dis,nm);e_fk(i,x)dfs_fk_utd(t_fk(i),bl[x].fr+dep[t_fk(i)]-dep[x],bl[x].sc);}
il void dfs_cal(ll x)
{
ll siz=sz[x];
e_fk(i,x)
{
ll sn=chd(t_fk(i),x);dfs_cal(t_fk(i));
siz-=sz[sn];
if(bl[t_fk(i)]==bl[x])siz+=sz[sn]-sz[t_fk(i)];
else
{
ll tmp=t_fk(i);
my(j,,)
if(mp(dep[t_fk(i)]-dep[fa[tmp][j]]+bl[t_fk(i)].fr,bl[t_fk(i)].sc)<mp(dep[fa[tmp][j]]-dep[x]+bl[x].fr,bl[x].sc))tmp=fa[tmp][j];
as[bl[t_fk(i)].sc]+=sz[tmp]-sz[t_fk(i)];siz+=sz[sn]-sz[tmp];
}
bl[t_fk(i)]=mp(inf,);
}
as[bl[x].sc]+=siz;
head_fk[x]=;
}
il void cal()
{
dfs_fk_dtu(rt);dfs_fk_utd(rt,bl[rt].fr,bl[rt].sc);
/*以上都是正确dei!然而就这个cal出错辣1551*/
if(!ext[])--ld_cnt;
dfs_cal(rt);rp(i,,ld_cnt)printf("%lld ",as[output[i]]),as[output[i]]=,ext[output[i]]=;printf("\n");
} int main()
{
freopen("sjs.in","r",stdin);freopen("sjs.out","w",stdout);
n=read();rp(i,,n-){ll x=read(),y=read();ad_rl(x,y,);ad_rl(y,x,);}dfs_rl(,);
m=read();rp(i,,m){ld_cnt=read();rp(i,,ld_cnt)ext[output[i]=land[i]=read()]=;if(!ext[])land[++ld_cnt]=;build_fk();;cal();}
return ;
}
/*
,,,感jio自己命名有点儿玄学,,,在后边解释下好了quq
其实也麻油几个要解释的呢QAQ?
一个是rl-real,表示最开始的实树
一个是fk-fake,表示后来建起来的虚树
一个是utd-uptodown,表示从上往下更新
一个是dtu-downtoup,表示从下往上更新
好像也麻油辣?
*/
/*清零操作不要忘了,,,调死我了,,,wsl*/
这儿是代码,,,打死我了TT(然后灵巧的蛇皮命名方式写在后面辣!
洛谷P3233 世界树 [HNOI2014] 虚树的更多相关文章
- 洛谷P3233 世界树
题意:给定树上k个关键点,每个点属于离他最近,然后编号最小的关键点.求每个关键点管辖多少点. 解:虚树 + DP. 虚树不解释.主要是DP.用二元组存虚树上每个点的归属和距离.这一部分是二次扫描与换根 ...
- bzoj 2286(洛谷 2495) [Sdoi2011]消耗战——虚树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2286 https://www.luogu.org/problemnew/show/P2495 ...
- ●洛谷P3233 [HNOI2014]世界树
题链: https://www.luogu.org/problemnew/show/P3233题解: 虚树,dp,倍增. 首先对于每个询问,要把虚树建出来,这一步就从略了.这里着重分享一下如何求答案. ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- 洛谷p3384【模板】树链剖分题解
洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...
- 洛谷 P3233 [HNOI2014]世界树(虚树+dp)
题面 luogu 题解 数据范围已经告诉我们是虚树了,考虑如何在虚树上面\(dp\) 以下摘自hzwer博客: 构建虚树以后两遍dp处理出虚树上每个点最近的议事处 然后枚举虚树上每一条边,考虑其对两端 ...
- 洛谷P3233 [HNOI2014]世界树
虚树= = #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring&g ...
- bzoj 3572 [Hnoi2014]世界树(虚树+DP)
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 645 Solved: 362[Submit][Status] ...
- BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】
题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. ...
随机推荐
- Android GIS +webservice
Android新手经典入门教程 Android开发教程(完全免费版) Android SDK v3.1.0 Android定位功能(一) Android定位功能(二) Android 百度地图开发(一 ...
- 性能优化系列八:MYSQL的配置优化
一.关键配置 1. 配置文件的位置 MySQL配置文件 /etc/my.cnf 或者 /etc/my.cnf.d/server.cnf 几个关键的文件:.pid文件,记录了进程id.sock文件,是内 ...
- (转) at&T语法格式 与 at&T - intel格式对比
原地址 示例: movl (%ebp), %eax, 等同于Intel格式中的 ] ,AT&T中,源操作数在左,目的操作数在右.“l”是Longword,相当于Intel格式中的dword p ...
- rem布局在react中的应用
摘要: 前面给大家分享了一个react项目(http://www.cnblogs.com/xiyangbaixue/p/4751904.html),这次对这个项目做了一些改进,增加了rem布局和对is ...
- [Object Tracking] Deep Boundary detection Tech
AR的要点之一便是精确跟踪 From: https://zhuanlan.zhihu.com/p/26848831?refer=dlclass Boundary Detection Benchmark ...
- ThinkingInJava 学习 之 0000003 控制执行流程
1. if-else 2. 迭代 1. while 2. do-while 3. for 4. 逗号操作符 Java里唯一用到逗号操作符的地方就是for循环的控制表达式. 在控制表达式的初始化和步进控 ...
- NUC972---Linux驱动开发
驱动开发是嵌入式 Linux 产品开发的重要组成部分,驱动是将芯片底层与Linux应用连接起来的桥梁.驱动程序的好坏直接影响和决定着产品的稳定性,稳定的驱动程序是产品可靠性的基石. 编写 Linux ...
- iOS(WKWebView)OC与JS交互 之三
随着H5功能愈发的强大,没进行过混合开发的小伙们都不好意思说自己能够独立进行iOS的app开发,在iOS7操作系统下,常用的native,js交互框架有easy-js,WebViewJavascr ...
- spark未授权RCE漏洞学习
Spark简介 spark是一个实现快速通用的集群计算平台.它是由加州大学伯克利分校AMP实验室 开发的通用内存并行计算框架,用来构建大型的.低延迟的数据分析应用程序.它扩展了广泛使用的MapRedu ...
- web开发之环境配置和文件系统
web开发中有jsp,html,css,java,pictures等文件和程序,怎么组织他们,使其正确加载,是一个比较大的问题,就像一团乱麻,解不开啊.IDE是个大管家,要对它非常熟悉才可以,跟顺利地 ...