LCA

倍增法求最近公共祖先

首先对于每个结点先进行dfs预处理它的深度,再记录下它们往父亲方向走2的0次,1次...k次步所到达的结点。在这里2的k次大于整棵树的最大深度。

预处理完后,需要查询两个点u,v的LCA时,先将u,v中深度较大的利用预处理的数组走到和另一个结点相同深度,操作次数不会超过log2|depth(u)-depth(v)|

接下来从k开始往下枚举,如果u和v往上走2的i次后不同那么它们一起往上走那么多步

预处理 O(nlogn)查询O(logn)

不仅如此我们可以动态地给树增加一些叶子结点,在预处理时还可以记录下这段路径权值最大值,最小值或权值和之类的信息。

Luogu P3379 https://www.luogu.com.cn/problem/P3379

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
const double PI = acos(-1.0);
typedef long long ll;
using namespace std; struct Edge {
int t, next;
}e[<<]; //开两倍
int head[], tot; void add_edge(int x, int y) {
e[++tot].t = y;
e[tot].next = head[x];
head[x] = tot;
} int depth[], fa[][], lg[]; void dfs(int now, int fath) { //now表示当前节点,fath表示其父亲节点
fa[now][] = fath;
depth[now] = depth[fath] + ;
for (int i = ; i <= lg[depth[now]]; i++) {
fa[now][i] = fa[fa[now][i - ]][i - ]; //算法核心
}
for (int i = head[now]; i; i = e[i].next) {
if (e[i].t != fath) dfs(e[i].t, now);
}
} int LCA(int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
while (depth[x] > depth[y])
x = fa[x][lg[depth[x] - depth[y]] - ]; //先跳到同一层
if (x == y) return x; //如果x==y那LCA一定就是x
for (int k = lg[depth[x]] - ; k >= ; k--) { //不断向上跳
if (fa[x][k] != fa[y][k]) { //因为要跳到LCA的下一层所以他们肯定不相等,不相等就跳过去
x = fa[x][k];
y = fa[y][k];
}
}
return fa[x][];
} int main() {
int n, m, s;
scanf("%d%d%d", &n, &m, &s);
for (int i = ; i <= n - ; i++) {
int x, y;
scanf("%d%d", &x, &y);
add_edge(x, y);
add_edge(y, x);
}
for (int i = ; i <= n; i++) { //预先算出log2(i)+1的值,用的时候可以直接调用
lg[i] = lg[i - ] + ( << lg[i - ] == i);
}
dfs(s, );
for (int i = ; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", LCA(x, y));
}
return ;
}

邻接表版本

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
const double PI = acos(-1.0);
typedef long long ll;
using namespace std; const int maxn = ;
int depth[maxn], fa[maxn][];
int lg[maxn];
vector<int> e[maxn];
void add_edge(int x, int y) {
e[x].push_back(y);
}
void dfs(int u, int last) { //last是u的父亲结点
depth[u] = depth[last] + ;
fa[u][] = last;
for (int i = ; i <=lg[depth[u]]; i++) {
fa[u][i] = fa[fa[u][i - ]][i - ];
}
for (int i = ; i < e[u].size(); i++) {
if (e[u][i] != last) dfs(e[u][i], u);
}
}
int lca(int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
while (depth[x] > depth[y]) {
x = fa[x][lg[depth[x]-depth[y]]-];
}
if (x == y) return x;
for (int k = lg[depth[x]]-; k >= ; k--) {
if (fa[x][k] != fa[y][k]) x = fa[x][k], y = fa[y][k];
//printf("%d\n", fa[x][0]);
}
return fa[x][];
}
int main() {
int n, m, s, x, y;
scanf("%d%d%d", &n, &m, &s);
for (int i = ; i <= n; i++) {
lg[i] = lg[i - ] + ( << lg[i - ] == i);
}
for (int i = ; i <= n - ; i++) {
scanf("%d%d", &x, &y);
add_edge(x, y);
add_edge(y, x);
}
dfs(s, );
for (int i = ; i <= m; i++) {
scanf("%d%d", &x, &y);
printf("%d\n", lca(x, y));
}
return ;
}

POJ 1330  (邻接表存储)

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
const double PI = acos(-1.0);
typedef long long ll;
using namespace std; int fa[][], depth[], d[];
vector<int> e[];
void dfs(int u) {
for (int i = ; i <= ; i++) {
fa[u][i] = fa[fa[u][i - ]][i - ];
}
for (int i = ; i < e[u].size(); i++) {
int v = e[u][i];
depth[v] = depth[u] + ;
fa[v][] = u;
dfs(v);
}
}
int lca(int u, int v) {
if (depth[u] > depth[v]) {
swap(u, v);
}
int t = depth[v] - depth[u];
for (int i = ; i >= ; i--) {
if ( << i & t) v = fa[v][i];
}
if (u == v) return u;
for (int i = ; i >= ; i--) {
if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
}
return fa[u][];
}
int main() {
int n, T;
scanf("%d", &T);
while (T--) {
memset(depth, , sizeof depth);
memset(fa, , sizeof fa);
memset(d, , sizeof d);
scanf("%d", &n);
int u, v;
for (int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
e[u].push_back(v);
d[v]++;
}
scanf("%d%d", &u, &v);
int rt = ;
for (int i = ; i <= n; i++) if (!d[i]) rt = i;
dfs(rt);
printf("%d\n", lca(u, v));
for (int i = ; i <= n; i++) {
e[i].clear();
}
}
return ;
}

CodeForces - 697C Lorenzo Von Matterhorn

不需要求出LCA   数的移动(二叉树编号)

#include<iostream>
#include<map>
using namespace std;
typedef unsigned long long ll;
map<ll,ll> mp; int main(){
int q;
int f;
ll l,r,w;
scanf("%d",&q);
for(int i=;i<q;i++){
scanf("%d",&f);
if(f==) {
scanf("%lld%lld%lld",&l,&r,&w);
while(l!=r){
if(l>r) mp[l]+=w,l/=;
else mp[r]+=w,r/=;
}
}
else {
scanf("%lld%lld",&l,&r);
ll ans=;
while(l!=r){
if(l>r) ans+=mp[l],l/=;
else ans+=mp[r],r/=;
}
printf("%lld\n",ans);
}
}
return ;
}

倍增应用

From OI wiki

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<cmath>
const double PI = acos(-1.0);
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std; const int mod = ; int modadd(int a, int b) {
if (a + b >= mod) return a + b - mod; //加快模运算
return a + b;
} int vi[];
int go[][]; //go[i][x]表示第x个点跳2^i步后的终点
int sum[][]; //sum[i][x]表示第x个点跳2^i步之后能获得的点权和 int main() {
int n, k;
scanf("%d%d", &n, &k);
for (int i = ; i <= n; i++) {
scanf("%d", &vi[i]);
}
for (int i = ; i <= n; i++) {
go[][i] = (i + k) % n + ;
sum[][i] = vi[i];
}
int logn = - __builtin_clz(n); //快捷的取2对数方法
for (int i = ; i <= logn; i++) {
for (int j = ; j <= n; j++) {
go[i][j] = go[i - ][go[i - ][j]];
sum[i][j] = modadd(sum[i - ][j], sum[i - ][sum[i - ][j]]);
}
} ll m;
scanf("%lld", &m); int ans = ;
int curx = ;
for (int i = ; m; i++) {
if (m & ( << i)) {
ans = modadd(ans, sum[i][curx]);
curx = go[i][curx];
m ^= 1ll << i; //将第i位置零 //1ll是64位的1
}
}
printf("%d", ans);
return ;
}

HZNU-ACM寒假集训Day9小结 倍增的更多相关文章

  1. 中南大学2019年ACM寒假集训前期训练题集(基础题)

    先写一部分,持续到更新完. A: 寒衣调 Description 男从戎,女守家.一夜,狼烟四起,男战死沙场.从此一道黄泉,两地离别.最后,女终于在等待中老去逝去.逝去的最后是换尽一生等到的相逢和团圆 ...

  2. 中南大学2019年ACM寒假集训前期训练题集(入门题)

    A: 漫无止境的八月 Description 又双叒叕开始漫无止境的八月了,阿虚突然问起长门在这些循环中团长哪几次扎起了马尾,他有多少次抓住了蝉等等问题,长门一共回复n个自然数,每个数均不超过1500 ...

  3. HZNU-ACM寒假集训Day8小结 最小生成树

    最小生成树(无向图) Kruskal 给所有边按从小到大排序 形成环则不选择(利用并查集) P1546 最短网络   https://www.luogu.com.cn/problem/P1546 #i ...

  4. HZNU-ACM寒假集训Day3小结 搜索

    简单搜索 1.DFS UVA 548 树 1.可以用数组方式实现二叉树,在申请结点时仍用“动态化静态”的思想,写newnode函数 2.给定二叉树的中序遍历和后序遍历,可以构造出这棵二叉树,方法是根据 ...

  5. HZNU-ACM寒假集训Day1小结 STL 并查集

    常用STL 1.优先队列 priority_queue 内部是用堆(heap)实现的 priority_queue<int> pq; 默认为一个“越小的整数优先级越低的优先队列” 对于一些 ...

  6. HZNU-ACM寒假集训Day12小结 数论入门 题解

    算不出的等式 BJOI2012 看到这题 真没什么办法 无奈看题解 1.注意到p/q 联想到斜率 2.注意到 [ ] 联想到整点 注意到k在变化,构造一次函数 f(x)=p/q*x ,g(x)=q/p ...

  7. HZNU-ACM寒假集训Day12小结 数论入门

    符号说明 a|b      a整除b (a,b)    a与b的最大公因数 [a,b]     a与b的最小公倍数 pα||a    pα|a但pα+1∤a a≡b(mod m) a与b对模m同余 a ...

  8. HZNU-ACM寒假集训Day11小结 贪心

    1.刘汝佳紫书区间问题三大情况 1.选择不相交区间 贪心策略:一定要选择第一个区间 2.区间选点问题 贪心策略:取最后一个点 3.区间覆盖问题: n个闭区间,选择尽量少的区间覆盖一条指定线段[s,t] ...

  9. HZNU-ACM寒假集训Day10小结 单调栈-单调队列

    数据结构往往可以在不改变主算法的前提下题高运行效率,具体做法可能千差万别,但思路却是有规律可循 经典问题:滑动窗口  单调队列O(n) POJ 2823 我开始写的: TLE 说明STL的库还是有点慢 ...

随机推荐

  1. JS开发常用工具函数

    1.isStatic:检测数据是不是除了symbol外的原始数据 function isStatic(value) { return ( typeof value === 'string' || ty ...

  2. 1_01_MSSQL课程_基础入门2

    1.数据库的迁移方案 ->分离 附加 ->权限问题: ->启用Administrator账号 ->把数据库文件放到默认的数据库文件存放目录. ->数据库文件兼容级别,设置 ...

  3. JS 判断是否为安卓或IOS系统

    其实很简单,代码如下<script type="text/javascript"> var device = navigator.userAgent; || devic ...

  4. docker学习笔记-01:docker基本原理

    一.docker原理 1.什么是docker:解决了运行环境和配置问题的容器,方便做持续集成并有助于整体发布的容器虚拟化技术. 2.虚拟机的缺点:(1)资源占用多:(2)冗余步骤多:(3)启动慢,分钟 ...

  5. Python 3.8 新功能【新手必学】

       Python 3.8 是 Python 编程语言的最新主要版本, 它包含许多新功能和优化.   Python 3.8 Python 3.8 的一些新功能包括: 1. 海象运算符   PS:很多人 ...

  6. 我的博客 Hexo 还是Jekyll

    我的博客 Hexo 还是Jekyll 标签(空格分隔): 博客 很喜欢找一些博客主题,目前发现几个比较不错的 Hexo: 阿里中间件 我的个人博客-Material主题 我的个人博客-Fluid主题 ...

  7. 022、Java中boolean的用法

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  8. NIO 聊天室代码实现

    服务器端 package com.ronnie.nio.groupChat; import java.io.IOException; import java.net.InetSocketAddress ...

  9. 吴裕雄--天生自然java开发常用类库学习笔记:Set接口

    import java.util.HashSet ; import java.util.Set ; public class HashSetDemo01{ public static void mai ...

  10. Problem I: Ingenious Lottery Tickets

    Problem I: Ingenious Lottery Tickets Your friend Superstitious Stanley is always getting himself int ...