模板:虚树

所谓虚树,就是虚了的树

(逃)

前言

在有些时候,我们只关心树上的某些特殊点,问题中的整体规模较大,但是这些特殊点往往比较稀疏,这个时候就可以使用虚树,只保留树上的关键点,从而大大缩小问题规模

引例

洛谷P3233 世界树

给出一个树和m个询问,每次询问给出k个特殊点,树上的每个结点都受最近的特殊点管辖,求每个特殊点管辖的结点数目
数据范围:n≤3∗105,m≤3∗105,∑k≤3∗105n\leq3*10^5,m\leq3*10^5,\sum k \leq3*10^5n3105,m3105,k3105

解析

首先考虑只有一次询问的时候如何做
只有我想到bfs了吗…
可以换根dp很简单的解决
但是本题每次dp一遍是nm的,无法接受

考虑使用虚树
首先,我们要找到所有的关键点
除了特殊点之外,我们还要选出一些非特殊点以保持树的形态不变
经过观察和题解,发现两两求出lca作为关键点即可
但是两两求是k2k^2k2的,无法接受
这里只有我想到根号分治了吗

引理:若x、y、z是dfs序单调递增的三个点,那么lca(x,z)lca(x,z)lca(x,z)必定是lca(x,y)lca(x,y)lca(x,y)lca(y,z)lca(y,z)lca(y,z)两者之一

证明…自己画画图吧
所以我们把关键点按dfs序排一下序,然后相邻求lca即可

求出关键点,我们还要在它们之间连边
这可以在确定关键点的时候顺便求出来
具体的实现,需要利用一个来进行
栈里存储的是一条当前的极右链
一本通的实现比较恶心,学习了洛谷上第一篇题解的写法,相对比较简洁

zhan[top=1]=v[1];
for(int i=2;i<=k;i++){int x=v[i],lca=Lca(x,zhan[top]);while(top>1&&dep[lca]<=dep[zhan[top-1]]){addline(zhan[top-1],zhan[top]);top--;}if(zhan[top]!=lca){addline(lca,zhan[top]);zhan[top]=lca;}zhan[++top]=x;
}
while(top>1) addline(zhan[top-1],zhan[top]),top--;
int rt=zhan[1];

然后就是dp部分
不在虚树上的点可以比较容易的确定归属
关键是在链两端所属不同时的链上的点
可以找到链上管辖示例的分界点
然后用子树大小减一减就出来了
还是不难理解的,具体看代码吧
写的有点恶心,但跑的还是挺快的

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf (n+1)
//#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=3e5+100;
const int M=2e5+10500;
const double eps=1e-5;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m;
int tim;
struct node{int to,nxt,w;
}p[N<<1];
int fi[N],cnt;
int jd[N];
inline void addline(int x,int y,int w){if(jd[x]!=tim){jd[x]=tim;fi[x]=-1;}if(jd[y]!=tim){jd[y]=tim;fi[y]=-1;}//printf("x=%d y=%d\n",x,y);p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return;
}int pos[N];
int sz[N],pl[N][20],dep[N];
void init(int x,int f){pl[x][0]=f;for(int k=1;pl[x][k-1];k++) pl[x][k]=pl[pl[x][k-1]][k-1];pos[x]=++tim;sz[x]=1;dep[x]=dep[f]+1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;init(to,x);sz[x]+=sz[to];}return;
}
inline int Lca(int x,int y){if(pos[x]<=pos[y]&&pos[y]<=pos[x]+sz[x]-1) return x;for(int k=19;k>=0;k--){int o=pl[x][k];if(!o||(pos[o]<=pos[y]&&pos[y]<=pos[o]+sz[o]-1)) continue;x=o;}return pl[x][0];
}
int bac[N],tag[N],v[N],ori[N];
int fa[N],zhan[N],top;
int dis[N],id[N];
bool cmp(int x,int y){return pos[x]<pos[y];
}
void dfs1(int x){if(tag[x]==tim){dis[x]=0;id[x]=x;}else dis[x]=1e9;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;dfs1(to);if(dis[x]>dis[to]+p[i].w||(dis[x]==dis[to]+p[i].w&&id[x]>id[to])){dis[x]=dis[to]+p[i].w;id[x]=id[to];}}
}
void dfs2(int x,int f,int fv){if(f){if(dis[x]>dis[f]+fv||(dis[x]==dis[f]+fv&&id[x]>id[f])){dis[x]=dis[f]+fv;id[x]=id[f];}}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;dfs2(to,x,p[i].w);}//printf("x=%d dis=%d id=%d\n",x,dis[x],id[x]);return;
}
inline int jump(int x,int w){for(int k=19;k>=0;k--){if(w<(1<<k)) continue;w-=(1<<k);x=pl[x][k];}return x;
}
void calc(int x){bac[id[x]]++;int lft=sz[x]-1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to,son=jump(to,p[i].w-1);lft-=sz[son];//printf("  x=%d to=%d -=%d+%d\n",x,to,siz[to],p[i].w-1);if(id[x]==id[to]) bac[id[x]]+=sz[son]-sz[to];else{int d=p[i].w+dis[to]-dis[x],add=(d-1+(id[x]<id[to]))/2;int pl=jump(to,p[i].w-1-add);bac[id[x]]+=sz[son]-sz[pl];bac[id[to]]+=sz[pl]-sz[to];//	printf("  x=%d to=%d add=%d x+=%d to+=%d\n",x,to,add,sz[son]-sz[pl],sz[pl]-sz[to]);}calc(to);}//printf("x=%d leftsiz=%d\n",x,lft);bac[id[x]]+=lft;
}
int main(){
#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);
#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();for(int i=1;i<n;i++){int x=read(),y=read();addline(x,y,1);addline(y,x,1);}init(1,0);m=read();for(tim=1;tim<=m;tim++){//printf("\ntim=%d\n",tim);int k=read();for(int i=1;i<=k;i++){v[i]=ori[i]=read();bac[v[i]]=0;tag[v[i]]=tim;fa[v[i]]=0;}sort(v+1,v+1+k,cmp);cnt=-1;zhan[top=1]=v[1];for(int i=2;i<=k;i++){int x=v[i],lca=Lca(x,zhan[top]);while(top>1&&dep[lca]<=dep[zhan[top-1]]){addline(zhan[top-1],zhan[top],dep[zhan[top]]-dep[zhan[top-1]]);top--;}if(zhan[top]!=lca){addline(lca,zhan[top],dep[zhan[top]]-dep[lca]);zhan[top]=lca;}zhan[++top]=x;}while(top>1) addline(zhan[top-1],zhan[top],dep[zhan[top]]-dep[zhan[top-1]]),top--;//printf("OK\n");int rt(zhan[1]);dfs1(rt);dfs2(rt,0,0);bac[id[rt]]+=n-sz[rt];calc(rt);for(int i=1;i<=k;i++) printf("%d ",bac[ori[i]]);putchar('\n');}return 0;
}
/*
10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
1
5
2 9 3 5 8
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317396.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P8340-[AHOI2022]山河重整【dp,倍增】

正题 题目链接:https://www.luogu.com.cn/problem/P8340 题目大意 给出一个nnn和模数PPP。求有多少个在1∼n1\sim n1∼n中选择若干个数的集合SSS&#xff0c;满足1∼n1\sim n1∼n中的每个数都可以表示成SSS的某个子集的和。 1≤n≤5105,2≤P≤1.11091\leq n\leq 5\times 10^5…

[LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心+贪心)

[LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相 description solution 一个到所有节点距离和最小的节点 ⇔\Leftrightarrow⇔ 树的重心&#xff08;满足最重的儿子最轻&#xff0c;每个儿子siz≤n2\le\frac{n}{2}≤2n​&#xff09; 显然原树的重心答案为0 对于点iii&am…

由优劣语言之争引起的思考

由优劣语言之争引起的思考#欲使其灭亡&#xff0c;必使其疯狂昨天上午由阿里云中间件公众号和架构师小秘圈公众号发布的一篇文章《天天敲代码会使人变聪明么》在.net开发者中掀起了一阵巨浪&#xff0c;文章中提到的语言的先进与落后之争让基于.net开发者们义愤填膺&#xff0c…

P1527 [国家集训队]矩阵乘法

P1527 [国家集训队]矩阵乘法 题意&#xff1a; 给你一个 nn 的矩阵&#xff0c;每次询问一个子矩形的第 k 小数。 题解&#xff1a; 整体二分稍微加强化 模板题是一个序列&#xff0c;现在升级成一个矩阵求&#xff0c;做法和原理都是一样的 使用整体二分解决的题目&#x…

[LOJ #521]「LibreOJ β Round #3」绯色 IOI(抵达)(结论)

#521. 「LibreOJ β Round #3」绯色 IOI&#xff08;抵达&#xff09; description solution 因为点的庇护所不能为自身&#xff0c;题目背景在树上&#xff0c;有结论一定是两个相邻点互为庇护所 所以树一定要能两两完美匹配才有解 判断完有解后就是构造解了&#xff0c;…

UOJ#310-[UNR #2]黎明前的巧克力【FWT】

1# 正题 题目链接:https://uoj.ac/problem/310 题目大意 给出一个长度为nnn的序列&#xff0c;求有多少种方案找出两个集合S,TS,TS,T使得这两个集合的异或和相等。 1≤n≤1061\leq n\leq 10^61≤n≤106 解题思路 可以转换为找到一个异或和为000的集合SSS&#xff0c;产生2∣S…

ybtoj洛谷P4426:毒瘤(虚树,环套树,暴力)

传送门 解析 顾名思义&#xff0c;十分毒瘤 但有一说一&#xff0c;相对来说这题没有之前做的那两个黑题那么&#xff08;重读&#xff09;恶心 而且本题如果放在考场上&#xff0c;暴力枚举非树边的状态dp就可以拿到70分的好成绩&#xff08;改一改能改到75&#xff09; 现…

微软是如何使用 C# 重写 C# 编译器并将其开源的

Roslyn 是 C# 和 Visual Basic.NET 开源编译器的代号。这篇文章将介绍它是如何从微软过去的十年至暗时刻走出来&#xff0c;成为开源跨平台的 C# 和 VB 公共语言引擎。我于 2005 年加入微软&#xff0c;也就是在.NET 2.0 发布之前&#xff0c;当时微软内部已经开始在讨论 Rosly…

P3332 [ZJOI2013]K大数查询(整体二分做法)

P3332 [ZJOI2013]K大数查询 题意: 题解&#xff1a; 利用整体二分来做&#xff0c;这个题和P3834 【模板】可持久化线段树 2的区别在于本题的修改是区间修改&#xff0c;所以将里面的树状数组改成线段树就行&#xff0c;区间修改区间查询 但是不知道为什么我调了一阵子也不对…

[APIO2020]交换城市(交互+kruskal重构树)

[APIO2020]交换城市 description solution 如果u,vu,vu,v存在于一条链上&#xff08;只有两个点度数为111其余点度数为222&#xff09;则无解&#xff0c;否则必有解 如图&#xff0c;不管是哪个点度数>2>2>2&#xff0c;都可以有解 以蓝色为例&#xff0c;第二个…

P3320:寻宝游戏(生成树)

解析 大结论题… 实在是不知道这题和虚树有半毛钱关系吗… 引理 给出一个按照dfs排列的点集S{a1,a2…ak} 它们的极小联通子树的边权和的二倍等于∑dis(a1,a2)dis(a2,a3)...dis(ak−1,ak)dis(ak,a1)\sum dis(a_1,a_2)dis(a_2,a_3)...dis(a_k-1,a_k)dis(a_k,a_1)∑dis(a1​,a2​…

P5333-[JSOI2019]神经网络【dp,容斥】

正题 题目链接:https://www.luogu.com.cn/problem/P5333 题目大意 给出nnn棵树&#xff0c;第iii棵树有kik_iki​个点&#xff0c;每棵树上的每个点和其它树上的所有点都有连边。 求这棵树有多少条哈密顿回路。 答案对998244353998244353998244353取模。 ∑i1nki≤5000\sum…

如何在ASP.NET Core程序启动时运行异步任务(1)

原文&#xff1a;Running async tasks on app startup in ASP.NET Core (Part 1)作者&#xff1a;Andrew Lock译者&#xff1a;Lamond Lu背景当我们做项目的时候&#xff0c;有时候希望自己的ASP.NET Core应用在启动前执行一些初始化逻辑。例如&#xff0c;你希望验证配置是否合…

扫描线讲解

参考文章&#xff1a; 线段树扫描线&#xff08;有关扫描线的理解&#xff09; 线段树扫描线&#xff08;基本原理&#xff09; 扫描线 第二个文章里面的图很生动&#xff1a; 我总结一下就是&#xff1a;将所给图形的横坐标全部记录&#xff0c;纵坐标记录为扫描线 然后对与…

P5400-[CTS2019]随机立方体【二项式反演,计数】

正题 题目链接:https://www.luogu.com.cn/problem/P5400 题目大意 有一个nmln\times m\times lnml的三维网格&#xff0c;要在每个格子处填上一个数&#xff0c;要求填的数中1∼nml1\sim n\times m\times l1∼nml都恰好出现了一次。 一个极大值被定义为这个格子比其他与它至…

「CEOI2019」魔法树(DP+差分启发式合并)

「CEOI2019」魔法树 description solution 设dpi,j:idp_{i,j}:idpi,j​:i子树在jjj时刻的最大果汁量&#xff0c;显然dpi,jdp_{i,j}dpi,j​在jjj是单调递增的 dpi,jmax⁡(dpi,j,dpi,j−1)dp_{i,j}\max(dp_{i,j},dp_{i,j-1})dpi,j​max(dpi,j​,dpi,j−1​) iii不收获 dpi,j∑…

梁迪:我为MVP骄傲,《微软最有价值专家奖励计划介绍》附专题视频

题记&#xff1a;有些事情&#xff0c;比 MVP 更加不朽&#xff0c;浩气长空&#xff0c;日月星汉&#xff0c;我们为 MVP 和那些心目中的“MVP”感到骄傲。微软 MVP 是一种追求&#xff0c;不必要去强求&#xff0c;但 MVP 必定是俱乐部发展的根基础。火车跑得快全凭车头带&am…

CF1472(div3):总结

文章目录前言A. Cards for Friends题意简述解析代码B. Fair Division题意简述解析代码C. Long Jumps题意简述解析代码D. Even-Odd Game题意简述解析代码E. Correct Placement题意简述解析代码F. New Years Puzzle题意简述解析代码G. Moving to the Capital题意简述解析代码前言…

How Much Memory Your Code Is Using? Gym - 101955J

How Much Memory Your Code Is Using? Gym - 101955J 题意&#xff1a; t组数据&#xff0c;每组数据会有n个定义类型的方式&#xff0c;给你每个类型所占字节&#xff0c;问一共占了多少字节&#xff0c;最终答案按照Kibibyte单位输出&#xff0c;并向上取整 题解&#xf…

P3295 [SCOI2016]萌萌哒(DP+倍增)

P3295 [SCOI2016]萌萌哒 description solution 强制部分区间相同&#xff0c;很容易就想到了并查集&#xff0c;直接暴力并查集合并是O(n2)O(n^2)O(n2)的 只需要考虑那一个数据结构将其转化成O(nlog⁡n)O(n\log n)O(nlogn)的 树之类的就不考虑了&#xff0c;一段一段的区间…