lca

51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

纵然是瞬间 提交于 2019-12-07 11:37:28
LCA裸题 只有代码无原理,给自己复习用 1. ST表(这题2^10就够了) 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=2e3+50; 5 6 int cnt,dfn[maxn],dep[maxn],dp[maxn][21],lg2[maxn],dis[maxn],w[maxn][maxn]; 7 std::vector<int> G[maxn]; 8 void dfs(int u,int fa){ 9 dis[u]=dis[fa]+w[u][fa]; 10 dfn[u]=++cnt; dep[u]=dep[fa]+1; dp[cnt][0]=u; 11 for(int i=0,v;i<G[u].size();i++){ 12 if((v=G[u][i])==fa) continue; 13 dfs(v,u); 14 dp[++cnt][0]=u; 15 } 16 } 17 void st(){ 18 for(int i=2;i<=cnt;i++) lg2[i]=lg2[i>>1]+1; 19 for(int j=1;j<=20;j++){ 20 for(int i=1;i+(1<<j)-1<=cnt;i++){ 21 int r=i+(1<<(j-1)); 22 dp[i][j] =

一般图最大带权匹配:高级带花树

故事扮演 提交于 2019-12-06 04:42:00
有个两百多行的板子,没有注释,看着好像挺对的,先挖个坑以后填。 1 #include <bits/stdc++.h> 2 #define N 810 3 using namespace std; 4 typedef long long ll; 5 inline int read() 6 { 7 int x=0,f=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} 10 return x*f; 11 } 12 struct edge{int u,v,w;}mps[N][N]; 13 int n,m,mat[N],pre[N],bl[N],fa[N],tim;ll totw=0; 14 int sign[N],lab[N],slacku[N],blofm[N][N],tot,mx; 15 vector <int> leaves[N]; 16 int q[N],hd; 17 inline int calc_e(const edge &e) 18 { 19 return lab[e.u]+lab[e.v]-mps[e.u][e.v].w*2; 20 } 21 inline

Luogu P5327 [ZJOI2019]语言

纵然是瞬间 提交于 2019-12-06 00:31:35
题目 首先我们有这样一个暴力: 对于每个点,我们把覆盖到了它的链的两段拿出来作为关键点,那么这个点能够到达的点就是这些关键点作为极远点的生成树上的点。 我们把所有的关键点按dfs序排序,从小到大枚举,那么对于一个关键点 \(d_i\) ,它会造成 \(dep_{d_i}-dep_{lca(d_i,d_{i-1})}\) 的贡献。(这里建议画图理解一下) 为了方便,我们强制把 \(1\) 作为关键点,那么最后减去 \(dep_{lca(d_1,d_m)}\) (假设总共有 \(m\) 个关键点)即所有关键点的 \(lca\) 的深度即可。 我们考虑用线段树维护这个过程。 以dfs序为下标,线段树的节点记录当前区间点集的生成树大小,dfs序最小的和最大的点。我们在pushup的时候完成减去 \(dep_{lca(u,v)}\) ( \(u\) 为线段树左孩子中dfs序最大的点, \(v\) 为线段树右孩子中dfs序最小的点)的操作。查询的时候用根节点的答案减去所有点的 \(lca\) 的深度即可。 我们再考虑优化这个暴力。 对于一条路径 \(s-t\) ,我们会把所有 \(s-t\) 上的节点都选 \(s,t\) 两点,这个可以用树上查分解决。 然后我们要实现把儿子的信息传给父亲,线段树合并解决。 因为总插入的信息是 \(n\) 级别的,所以线段树合并复杂度为 \(O(n\log n)

Count on a tree(树上路径第K小)

旧时模样 提交于 2019-12-05 20:59:31
题目链接: https://www.spoj.com/problems/COT/en/ 题意:求树上A,B两点路径上第K小的数 思路:主席树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上。 比如说我们从一棵树的根节点进行DFS,得到根节点到各节点的距离dist[x]——这是一个根-x路径上点与根节点距离的前缀和。 利用这个前缀和,我们可以解决一些树上任意路径的问题,比如在线询问[a,b]点对的距离——答案自然是dist[a]+dist[b]-2*dist[lca(a,b)]。 DFS遍历整棵树,然后在每个节点上建立一棵线段树,某一棵线段树的“前一版本”是位于该节点父亲节点fa的线段树。 利用与之前类似的方法插入点权(排序离散)。那么对于询问[a,b],答案就是root[a]+root[b]-root[lca(a,b)]-root[fa[lca(a,b)]]上的第k大。 #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<algorithm> #include<map> #include<vector> #include<string> #include<set> #define ll long long #define maxn 100007 using

ZJOI2016 大森林

谁都会走 提交于 2019-12-05 18:06:53
大森林 小Y家里有一个大森林,里面有 \(n\) 棵树,编号从 \(1\) 到 \(n\) 。一开始这些树都只是树苗,只有一个节点,标号为 \(1\) 。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。小Y掌握了一种魔法,能让第 \(l\) 棵树到第 \(r\) 棵树的生长节点长出一个子节点。同时她还能修改第 \(l\) 棵树到第 \(r\) 棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢? Input 第一行包含 \(2\) 个正整数 \(n,m\) ,共有 \(n\) 棵树和 \(m\) 个操作。接下来 \(m\) 行,每行包含若干非负整数表示一个操作,操作格式为: 0 l r 表示将第 \(l\) 棵树到第 \(r\) 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 \(0\) 号操作叶子标号加 \(1\) (例如,第一个 \(0\) 号操作产生的子节点标号为 \(2\) ), \(l\) 到 \(r\) 之间的树长出的节点标号都相同。保证 \(1≤l≤r≤n\) 。 1 l r x 表示将第 \(l\) 棵树到第 \(r\) 棵树的生长节点改到标号为 \(x\) 的节点。对于 \(i (l≤i≤r)\) 这棵树,如果标号 \(x\) 的点不在其中,那么这个操作对该树不产生影响。保证 \(1≤l≤r

最近公共祖先LCA(我们的LCA是谁呢)

眉间皱痕 提交于 2019-12-05 09:17:14
P3379 【模板】最近公共祖先(LCA) 例子 LCA(13,14)=12 LCA(13,7)=3 LCA(7,11)=2 LCA(11,2)=2 好了,了解以后我们就来康康怎么求吧 暴力LCA 如果找LCA(6,8),我们就要先让它们的深度相等。此时(deep[1]=0)deep[6]=4,deep[8]=3,我们就先让节点6爬到节点5 然后就是愉快的一起爬 让它们一层一层地向上爬,知道爬到同一节点 但是都知道,一旦这棵树有点高,like this,就会TTT 因为这样爬着太慢了 (青蛙爬树都知道跳着爬) 倍增LCA 所以我们升级了,会跳着爬了 但是怎么升呢,大家都知道,计算机和二进制都离不开关系 所以当然是按照2的次方来跳,不过我们不是从小往大(1,2,4,8,16,32,64...),而是从大到小(...64,,32,16,8,4,2,1)(因为从小到大加着会超过,到时候很麻烦) 所以我们跳的时候就还要计算一下你这么跳会到哪个节点去(不然你乱跳啊) 总所周知,1+1=2 (这不是废话吗) 1 void dfs(int x,int fa) 2 { 3 deep[x]=deep[fa]+1; 4 f[x][0]=fa; 5 for(int i=1;(1<<i)<=deep[x];i++) 6 { 7 f[x][i]=f[f[x][i-1]][i-1]; 8 } 9 for

[NOIP2016] 天天爱跑步 解题报告

旧城冷巷雨未停 提交于 2019-12-05 05:17:04
题意 一棵 \(n\) 个节点的树, 树的每个节点上有一个观察员, 每一个观察员的观察时刻为 \(time_i\) , 有 \(m\) 个玩家, 每个玩家在 \(0\) 时刻时从起点 \(s_i\) 开始跑步, 每时刻经过一个节点, 沿着最短路径向终点 \(t_i\) 跑去. 求每个观察员能观察到的玩家数量. 思路 暴力枚举每个玩家的行进路线一定是 \(O(n^2)\) 的, 不可行, 那么考虑枚举每一个观察员, 求它能观察到多少个选手. 若观察员 \(x\) 位于 \(s_i\) 到 \(lca_i\) 的路径上, 那么 \(x\) 能观察到 \(i\) 的条件为 \[ time_x = dep_{s_i} - dep_x \] 转化一下变为, \[ time_x+dep_x = dep_{s_i} \] 若 \(x\) 位于 \(t_i\) 到 \(lca_i\) 的路径上, 那么 \(x\) 能观察到 \(i\) 的条件为 \[ time_x = dis_{s_i \to t_i} - (dep_t - dep_x) \] 转化, \[ time_x - dep_x = dis - dep_t = dep_s - 2*dep_{lca_i} \] 看起来树上差分, 枚举每个点的子树, 开个桶记录就好了. 但有个问题, 就是之前的桶会影响当前枚举到的点. 我的做法比较蠢,

LCA 倍增算法模板

做~自己de王妃 提交于 2019-12-05 00:53:38
. 1 #include <cstring> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 using namespace std; 8 const int N=10000+5; 9 vector <int> son[N]; 10 int T,n,depth[N],fa[N][20],in[N],a,b; 11 void dfs(int prev,int rt){ 12 depth[rt]=depth[prev]+1; 13 fa[rt][0]=prev; 14 for (int i=1;i<20;i++) 15 fa[rt][i]=fa[fa[rt][i-1]][i-1]; 16 for (int i=0;i<son[rt].size();i++) 17 dfs(rt,son[rt][i]); 18 } 19 int LCA(int x,int y){ 20 if (depth[x]<depth[y]) 21 swap(x,y); 22 for (int i=19;i>=0;i--) 23 if (depth[x]-(1<<i)>=depth[y]) 24 x=fa[x][i]; 25 if (x==y) 26

LCA

别说谁变了你拦得住时间么 提交于 2019-12-04 14:04:38
LCA 最近公共祖先 倍增 在线算法 时间复杂度 \(O((n+q)\log\ n)\) 空间复杂度 \(O(n \log n)\) fa[x][k] 表示 \(x\) 的 \(2^k\) 祖先 dep[x] 表示 \(x\) 的深度 log[x] 表示 \(log_2\ x\) void pre_lca(int now,int father) //预处理LCA { dep[now]=dep[father]+1; fa[now][0]=father; for(int i=1;(1<<i)<=dep[now];i++) fa[now][i]=fa[fa[now][i-1]][i-1]; for(int i=head[now];i;i=edge[i].next) if(edge[i]!=father) pre_lca(edge[i].to,now); } void pre_log() //预处理log_2 方便查询 { log[0]=-1; for(int i=1;i<=MAX;i++) log[i]=log[i>>1]+1; } int lca(int x,int y) //求x y两点的LCA { if(dep[x]<dep[y]) //令x深度比y大 swap(x,y); while(dep[x]>dep[y]) //令x向上跳 直到和y同一高度 x=fa[x][log[dep

LCA

萝らか妹 提交于 2019-12-04 13:16:09
LCA #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define LL long long using namespace std; inline int read() { int z=0,b=1;char cs=getchar(); while(cs<'0'||cs>'9'){if(cs=='-')b=-1;cs=getchar();} while(cs>='0'&&cs<='9'){z=z*10+cs-'0';cs=getchar();} return z*b; } const int N=5e5+5; struct graph { int to,next; }gr[N<<1]; int n,m,s,cnt,head[N],dep[N],f[N][30]; void border(int u,int v) { gr[++cnt]=(graph){v,head[u]}; head[u]=cnt; return; } void pre_deal(int u,int fa) { dep[u]=dep[fa]+1; for(int i=1;i<=20;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u]