初涉倍增&&LCA【在更】
一种特殊的枚举算法
什么是倍增
顾名思义,即每一次翻倍增加。那么,这样我们就有了一种$O(logn)$阶的方法处理枚举方面的问题了。
参考:【白话系列】倍增算法
一些题目
【倍增】luoguP1613 跑路
题目描述
小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零。可是小A偏偏又有赖床的坏毛病。于是为了保住自己的工资,小A买了一个十分牛B的空间跑路器,每秒钟可以跑2^k千米(k是任意自然数)。当然,这个机器是用longint存的,所以总跑路长度不能超过maxlongint千米。小A的家到公司的路可以看做一个有向图,小A家为点1,公司为点n,每条边长度均为一千米。小A想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司。数据保证1到n至少有一条路径。
数据范围
50%的数据满足最优解路径长度<=1000;
100%的数据满足n<=50,m<=10000,最优解路径长度<=maxlongint。
题目分析
首先,显然这题是不能求最短路的跑路次数的。那么我们用bool类型的$f[i][j][t]$表示$i$到$j$存在长度为$2^t$的路径。
这样做可以使得$dis[i][j]$表示的是从$i$到$j$的最短跑路次数,因而最后用floyd求解最短路就好了。
#include<bits/stdc++.h>
const int maxn = ; bool f[maxn][maxn][];
int dis[maxn][maxn];
int n,m; int main()
{
scanf("%d%d",&n,&m);
memset(dis, 0x3f3f3f3f, sizeof dis);
for (int i=; i<=m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
f[x][y][] = ;
dis[x][y] = ;
}
for (int t=; t<=; t++)
for (int k=; k<=n; k++)
for (int i=; i<=n; i++)
for (int j=; j<=n; j++)
if (f[i][k][t-]&&f[k][j][t-]){
f[i][j][t] = ;
dis[i][j] = ;
}
for (int k=; k<=n; k++)
for (int i=; i<=n; i++)
for (int j=; j<=n; j++)
if (dis[i][k]+dis[k][j] < dis[i][j])
dis[i][j] = dis[i][k]+dis[k][j];
printf("%d\n",dis[][n]);
return ;
}
【LCA】luoguP3379 【模板】最近公共祖先(LCA)
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入输出格式
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
题目分析
呃这是一个裸的LCA题,那么就讲讲模拟法和倍增法吧(RMQ暂且不提)
模拟法
为了查询LCA(x,y),我们从x开始一直向上染色。再从y开始一直向上查询,最先查询到的染色过的点就是LCA(x,y)。
有一个技巧,把染色的vis开成int数组,这样每一次就不用memset了(很慢的)
#include<bits/stdc++.h>
const int maxn = ; std::vector<int> f[maxn];
int fa[maxn];
int n,m,s;
int vis[maxn]; int read()
{
char ch = getchar();
int num = ;
for (; !isdigit(ch); ch = getchar());
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
return num;
}
void buildStructure(int now)
{
for (unsigned int i=; i<f[now].size(); i++)
if (!fa[f[now][i]])
{
fa[f[now][i]] = now;
buildStructure(f[now][i]);
}
}
int main()
{
n = read(), m = read(), s = read();
for (int i=; i<n; i++)
{
int x = read(), y = read();
f[x].push_back(y), f[y].push_back(x);
}
fa[s] = s;
buildStructure(s);
fa[s] = ;
for (int i=; i<=m; i++)
{
int x = read(), y = read();
for (; x; x = fa[x]) vis[x] = i;
for (; y; y = fa[y])
if (vis[y] == i)
break;
printf("%d\n",y);
}
return ;
}
当然以上做法是过不了这题的
倍增法
倍增的话,算是一种对于模拟法的优化吧。
我们每一次不止跳一步,而是以$2^i$步数向上跳。
那么就需要O(nlogn)预处理一些东西,查询则是O(logn)的。
参考:
3.LCA详解
#include<bits/stdc++.h>
const int maxn = ;
const int logMaxn = ; int n,m,s;
int deep[maxn],p[maxn][logMaxn];
std::vector<int> f[maxn]; inline int read()
{
char ch = getchar();
int num = ;
for (; !isdigit(ch); ch = getchar());
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
return num;
}
void dfs(int now, int fa) //递归预处理
{
deep[now] = deep[fa]+;
p[now][] = fa;
for (int i=; (<<i)<=deep[now]; i++)
p[now][i] = p[p[now][i-]][i-];
for (unsigned int i=; i<f[now].size(); i++)
if (f[now][i]!=fa)
dfs(f[now][i], now);
}
int lca(int x, int y) //倍增LCA
{
if (deep[x] > deep[y]) std::swap(x, y);
for (int i=logMaxn-; i>=; i--)
if (deep[x]<=deep[y]-(<<i))
y = p[y][i];
if (x==y) return x;
for (int i=logMaxn-; i>=; i--)
if (p[x][i]==p[y][i])
continue;
else x = p[x][i], y = p[y][i];
return p[x][];
}
int main()
{
n = read(), m = read(), s = read();
register int i,x,y;
for (i=; i<n; i++)
{
x = read(), y = read();
f[x].push_back(y), f[y].push_back(x);
}
dfs(s, );
for (i=; i<=m; i++)
{
x = read(), y = read();
printf("%d\n",lca(x, y));
}
return ;
}
【LCA】luoguP3398 仓鼠找sugar
题目描述
小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?
小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!
输入输出格式
输入格式:
第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。
接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。
接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。
输出格式:
对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。
说明
__本题时限1s,内存限制128M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。__
20%的数据 n<=200,q<=200
40%的数据 n<=2000,q<=2000
70%的数据 n<=50000,q<=50000
100%的数据 n<=100000,q<=100000
题目分析
题目大意就是判断树上(a,b)与(c,d)两条路径之间有没有交点。
看上去很唬人的样子对吧……
【待更】其实我也觉得很唬人
初涉倍增&&LCA【在更】的更多相关文章
- 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)
洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...
- 倍增LCA学习笔记
前言 "倍增",作为一种二进制拆分思想,广泛用于各中算法,如\(ST\)表,求解\(LCA\)等等...今天,我们仅讨论用该思想来求解树上两个节点的\(LCA\)(最近公共祖先 ...
- [BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)
4568: [Scoi2016]幸运数字 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 2131 Solved: 865[Submit][Statu ...
- 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增
倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...
- cogs 1588. [USACO Feb04]距离咨询 倍增LCA
1588. [USACO Feb04]距离咨询 ★★ 输入文件:dquery.in 输出文件:dquery.out 简单对比时间限制:1 s 内存限制:256 MB [题目描述] 农夫 ...
- [板子]倍增LCA
倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...
- 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]
题目描述 Farmer John has installed a new system of pipes to transport milk between the stalls in his b ...
- Gym100685G Gadget Hackwrench(倍增LCA)
题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...
- Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]
题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_di ...
随机推荐
- java面试基础问题
1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致. 2.Java有 ...
- 最新的vue没有dev-server.js文件,如何进行后台数据模拟?
最新的vue里dev-server.js被替换成了webpack-dev-conf.js 在模拟后台数据的时候直接在webpack-dev-conf.js文件中修改 第一步,在const portfi ...
- slice方法可以将“类似数组的对象”变成真正的数组 (遇到时候再研究一次)
典型的“类似数组的对象”是函数的arguments对象,以及大多数 DOM 元素集,还有字符串. // arguments对象 function args() { return arguments } ...
- 解决https接口 以及谷歌错误
<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content"& ...
- 洛谷 P1121 环状最大两段子段和
https://www.luogu.org/problemnew/show/P1121 不会做啊... 看题解讲的: 答案的两段可能有两种情况:一是同时包含第1和第n个,2是不同时包含第1和第n个 对 ...
- springmvc写了方法无法访问
1.检查是否添加了@controller注解 2.在springmvc.xml里添加controller注解扫描 3.在applicationContext.xml里添加service扫描,给mapp ...
- Mex(线段树的巧妙应用)
题目要求求某段区间第一个没有出现的数(0,1,2,3....) ,对于所有的区间,我们把这样的数加起来最后得到一个结果. 首先,我们要求出这样的数,然后还得列举出所有的区间,复杂度太大了. 换种思路, ...
- 发布好的SDE 如何注册,让数据库更新 实现arcgis 服务更新
1, 打开 MXD 文件,前期已经发布的文件 右键 service peopertisers 右键 Service Property 出现如下界面: “+”号 需要需要选择SDE库 不需要 选择 ...
- aspectj xml
1.接口和类 1.1 ISomeService 接口 public interface ISomeService { public void doSome(); public void dade(); ...
- 断言assert用法
本文转自:http://blog.jobbole.com/76285/ 这个问题是如何在一些场景下使用断言表达式,通常会有人误用它,所以我决定写一篇文章来说明何时使用断言,什么时候不用. 为那些还不清 ...