lca

YLOJ 2019-10-23模拟赛

被刻印的时光 ゝ 提交于 2019-12-02 05:53:10
前言 补题。 这个YL怎么天天都有人AK,这是一群什么神仙啊 中央集权(emperor) 题目地址 终于出了一道裸题了 最小生成树 搞得我赶快复习了一下最小生成树的时间复杂度 Prim(堆优化): \(\text{O(m*logn)}\) Kruskal(要并查集): \(\text{O(m*logm)}\) 权衡一下,选择 Prim+堆优化,能过 √ 计算树(tree) 题目地址 看完题解不觉说出了一声NB 首先从这棵树的角度上冥思苦想都没有什么好办法,最多树上倍增什么的,感觉行不通 然而我们还是考虑到了一点,树上两点间的的路径一般可以分为两块(设两点为 \(x\) , \(y\) ) \(x->lca_{x,y}\) \(lca_{x,y}->y\) 以下我们就以 \(x\) , \(y\) , \(lca\) ( \(lca_{x,y}\) 简记为 \(lca\) )做例子 我们不妨换一个角度,从 \(lca\) 与 \(x\) , \(y\) 的关系上考虑。这里我们引入根 \(z\) ,想到 \(lca->z\) 与 \(x-z\) 有一条共同的路径 (敲黑板) 前方高能!!! 我们把 \(x->lca\) 这条路径上值的变换记作一次变换, \(x->y\) 的变换由两个变换 \(x->lca->y\) 组成,变换的结果是一个值,这个值就如题意所述,是这条路径上的表达式值。

SP913 QTREE2 - Query on a tree II

半腔热情 提交于 2019-12-02 02:38:58
洛咕 题意:给定一棵 \(n(n<=10000)\) 个点的树,边具有边权.要求以下操作: DIST a b 询问点a至点b路径上的边权之和. KTH a b k 询问点a至点b有向路径上的第k个点的编号. 倍增水题??? 对于第一个询问,只要记录每个节点到根节点1的 \(dist\) ,求出 \(LCA\) 之后,答案就是 \(dist[a]+dist[b]-2*dist[lca]\) . 对于第二个询问,因为倍增求 \(LCA\) 的时候预处理出了 \(f[i][j]\) 数组,表示i的 \(2^j\) 级祖先是谁,所以你只要分类讨论一下 \(a,b\) 的几种位置关系,倍增找就行了. #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<map> #include<set> #define ll long long using namespace std; inline int read(){ int x=0,o=1;char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')o=-1,ch=getchar();

CF504E Misha and LCP on Tree

无人久伴 提交于 2019-12-02 00:07:19
咕咕咕,还没调呢~ code: #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> #include <stack> #define setIO(s) freopen(s".in","r",stdin) using namespace std; namespace sam { #define N 1200004 int last,tot; int ch[N][27],pre[N],mx[N]; inline int extend(int c) { if(ch[last][c]) { int p=last; int q=ch[p][c]; if(mx[q]==mx[p]+1) last=q; else { int nq=++tot; mx[nq]=mx[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); pre[nq]=pre[q],pre[q]=nq; for(;p&&ch[p][c]==q;p=pre[p]) ch[p][c]=nq; last=nq; } } else { int np=++tot,p=last; mx[np]=mx[p]+1,last=np; for(;p&&!ch[p][c];p=pre[p])

DISQUERY - Distance Query

拟墨画扇 提交于 2019-12-01 23:25:09
洛咕 题意:给定有 \(n\) 个节点的树, 树上边有边权. 再给定 \(q\) 组询问, 每次询问两个点路径上的最小值和最大值. \(n,q<=100000.\) 询问树上路径点权的最值是树链剖分的模板题,然后本题给的是边权,就化边权为点权,从1号点为根 \(dfs\) 的时候,把 \(w[u][v]\) 这条边的边权给节点 \(v\) .然后就可以按照模板来做了 \(???\) 但是,这时根节点的权值为0,如果一条路径经过了根节点,其最小值会是根节点的权值0,所以我把根节点的权值赋值为 \(-1\) ,然后维护线段树区间最小值取 \(min\) 操作的时候,特判 \(-1\) 的情况(自己写个 \(min\) 函数就好了),因为边权为正(虽然题目好像并没有说明,当做默认了),所以对最大值的答案是没有影响的.然后就可以按照模板来做了 \(???\) 但是,会发现连样例一的第一组询问都过不去,注意到如果一组询问 \((x,y)\) ,设 \(lca=LCA(x,y)\) .查询答案的时候, \(lca\) 的权值对答案产生了影响,因为这条路径会经过 \(lca\) ,但是因为路径不会经过 \(lca\) 与 \(fa[lca]\) 这条边,所以实际上 \(lca\) 的权值是不能被考虑贡献的,所以我极其暴力地写了个线段树的单点修改操作,查询前把 \(lca\) 的权值改为 \(-1

绵阳东辰国际test201910.21

亡梦爱人 提交于 2019-12-01 20:23:10
爆零警告,昨天晚上睡得晚,考试的时候困死我了 分析: 哈密尔顿环:每个点只经过一次的路线,有哈密尔顿环的图叫哈密尔顿图 先考虑只是 一条链 很容易想到隔一个跳一次,这样 无论链有多长 一定是 从A出发,B回来 所以直接 拓展到树上 即可: 如 果当前节点深度是奇数,那么我们在DFS前输出这个点, 否则在DFS完所有孩子之 后再输出这个点。 part code: il void dfs(int u,int fa){ dp[u]=dp[fa]+1; if(dp[u]&1){printf("%d\n",u);} for(ri i=head[u];i;i=edg[i].next){ int to=edg[i].to; if(to==fa)continue; dfs(to,u); } if(!(dp[u]&1)){printf("%d\n",u);} } 什么跳两次的滚出 总结:有很多的dfs题代码很简单,却很容易陷阱去,导致思路开花,应该往简单的方向想 不禁想到一句诗: 众里寻他千百度,那人却在灯火阑珊处 分析: 首先用kmp或者哈希对每个 Ti,求出它在 S 中的匹配位置 那么这些位置 中至少得要删掉一个 考虑如果两个区间的R相等时,这时就只用管L最大的 证明 为什么因为先满足L较大的,其他的同R的肯定都满足了 而先满足L较小的,L较大的不一定满足,所以这样一定是最优的 于是对于 每个

倍增求LCA

血红的双手。 提交于 2019-12-01 19:58:00
P3379 【模板】最近公共祖先(LCA) 【题目大意】 给你树的节点个数 \(n\) ,询问个数 \(m\) 和树根 \(s\) , 输入 \(n,m,s\) ; 输入 \(n\) 对 \(x,y.\) 表示 \(x,y\) 结点之间有一条边 输入 \(m\) 对 \(a,b.\) 表示求 \(a,b\) 的最近公共祖先 【思路】 下面的解释均以这个图为例 今天用这道题来说一下倍增,先预处理出每个节点的深度,和lg数组,就是 \(log_2{i}\) 的值.所谓倍增,就是按 \(2\) 的倍数来增大,也就是跳 \(1,2,4,8,16,32……\) 不过在这我们不是按从小到大跳,而是从大向小跳,即按 \(……32,16,8,4,2,11\) 来跳,如果大的跳不过去,再把它调小。这是因为从小开始跳,可能会出现“悔棋”的现象。拿 \(5\) 为例,从小向大跳, \(5≠1+2+4\) ,所以我们还要回溯一步,然后才能得出 \(5=1+4\) ;而从大向小跳,直接可以得出 \(5=4+1\) 。这也可以拿二进制为例, \(5(101)\) ,从高位向低位填很简单,如果填了这位之后比原数大了,那我就不填,这个过程是很好操作的。 还是以 \(17\) 和 \(18\) 为例(此例只演示倍增,并不是倍增LCA算法的真正路径) \(17->3\) \(18->5->3\)

2019.10.16&17小结

柔情痞子 提交于 2019-12-01 17:20:46
话说也蛮久没写小结了,主要这两次考试失分严重,还是总结下吧。 10.16 T1 小奇挖矿2 100/0 【题目背景】 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎。 【问题描述】 现在有m+1个星球,从左到右标号为0到m,小奇最初在0号星球。 有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上。 由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球。每到一个星球,小奇会采走该星球上所有的原矿,求小奇能采到的最大原矿数量。 注意,小奇不必最终到达m号星球。 【输入格式】 第一行2个整数n,m。 接下来n行,每行2个整数ai,bi。 【输出格式】 输出一行一个整数,表示要求的结果。 【样例输入】 3 13 100 4 10 7 1 11 【样例输出】 101 【样例解释】 第一次从0到4,第二次从4到11,总共采到101单位原矿。 【数据范围】 对于20%的数据 n=1,m<=10^5 对于40%的数据 n<=15,m<=10^5 对于60%的数据 m<=10^5 对于100%的数据 n<=10^5,m<=10^9,1<=ai<=10^4,1<=bi<=m 一开始想的按照每个星球去dp,发现m太大,之后打表发现超过18的可以缩小为18,之后按照矿石位置dp,然而考场读写文件写挂

LCA算法的介绍与模板

别说谁变了你拦得住时间么 提交于 2019-12-01 12:24:09
对于一棵树,求两个节点的最近公共祖先(LCA)。   如下图:(以下数字代表对应编号的节点)    1 1 和 6 6 的 LCA 是 8 8 。    11 11 和 1 1 的 LCA 是 8 8 。    11 11 和 15 15 的 LCA 是 4 4 。    14 14 和 13 13 的 LCA 是 1 1 。 以洛谷P3379模板题为例 方法一:用倍增来在线求 LCA ,时间和空间复杂度分别是 O ( ( n + q ) log n ) O((n+q)log⁡n) 和 O ( n log n ) O(nlog⁡n) 。   对于这个算法,我们从最暴力的算法开始:     ①如果 a a 和 b b 深度不同,先把深度调浅,使他变得和浅的那个一样     ②现在已经保证了 a a 和 b b 的深度一样,所以我们只要把两个一起一步一步往上移动,直到他们到达同一个节点,也就是他们的最近公共祖先了。 #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxn=5e5+5; int lg[maxn];//log 2n向下取整 const int maxbit=20; vector<int>G[maxn]; int

【树上LCA】P1967 货车运输

夙愿已清 提交于 2019-12-01 11:48:46
1 #include<iostream> 2 #include<string> 3 #include<queue> 4 #include<stack> 5 #include<vector> 6 #include<map> 7 #include<cstdio> 8 #include<cstdlib> 9 #include<algorithm> 10 #include<set> 11 #include<iomanip> 12 #include<cstring> 13 #include<cmath> 14 #include<limits> 15 using namespace std; 16 17 #define au auto 18 #define debug(i) cout<<"<debug>"<<i<<"<\debug>"<<endl 19 #define mfor(i,a,b) for(register int i=(a);i<=(b);i++) 20 #define mrep(i,a,b) for(register int i=(a);i>=(b);i--) 21 #define LLL __int128 22 #define Re register 23 #define il inline 24 #define mem(a,b) memset(a,(b),sizeof(a))

【刷题】【LCA】跳跳棋

a 夏天 提交于 2019-12-01 11:42:48
(直接复制自luogu题解) 精巧的建模题。 划重点了划重点了一次只允许跳过1颗棋子,这句话是解题的关键。 手玩一下跳法,现有描述位置的递增三元组 (x,y,z) ( x , y , z ),研究它能够在一步之内跳到何处。 首先,中间的元素可以随意往两边跳到达状态 (2x-y,x,z) ( 2 x − y , x , z )和状态 (x,z,2z-y) ( x , z , 2 z − y ),注意到这两个三元组的边界是扩大了的。 对于两边的元素,设 d1=y-x,d2=z-y d 1 = y − x , d 2 = z − y 若 d1>d2 d 1 > d 2,则 c c可以往内跳,到达状态 (x,b-d2,b) ( x , b − d 2 , b ) 若 d2>d1 d 2 > d 1,同理。 注意到这次到达的状态三元组的边界是缩小了的,且跳法具有唯一性 若 d1=d2 d 1 = d 2,则边界没法缩小了,假定为边界条件。 对缩小边界的跳法具有唯一性这一性质,我们可以联想到什么呢? 将初始状态和目标状态同时缩小边界,看能否产生交集。 用树来描述这一个状态集合(树父亲的唯一性对应缩小边界的唯一性)。 到这里40分就拿到了。 但是我们发现,树的状态太多,无法存储。 只能每次在线询问需要的状态,复杂度为 O(d) O ( d ), d d的两个节点的相对深度。 感觉这样就像裸奔