一种特殊的枚举算法

什么是倍增

顾名思义,即每一次翻倍增加。那么,这样我们就有了一种$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求解最短路就好了。

参考:题解 P1613 【跑路】

  1. #include<bits/stdc++.h>
  2. const int maxn = ;
  3.  
  4. bool f[maxn][maxn][];
  5. int dis[maxn][maxn];
  6. int n,m;
  7.  
  8. int main()
  9. {
  10. scanf("%d%d",&n,&m);
  11. memset(dis, 0x3f3f3f3f, sizeof dis);
  12. for (int i=; i<=m; i++)
  13. {
  14. int x,y;
  15. scanf("%d%d",&x,&y);
  16. f[x][y][] = ;
  17. dis[x][y] = ;
  18. }
  19. for (int t=; t<=; t++)
  20. for (int k=; k<=n; k++)
  21. for (int i=; i<=n; i++)
  22. for (int j=; j<=n; j++)
  23. if (f[i][k][t-]&&f[k][j][t-]){
  24. f[i][j][t] = ;
  25. dis[i][j] = ;
  26. }
  27. for (int k=; k<=n; k++)
  28. for (int i=; i<=n; i++)
  29. for (int j=; j<=n; j++)
  30. if (dis[i][k]+dis[k][j] < dis[i][j])
  31. dis[i][j] = dis[i][k]+dis[k][j];
  32. printf("%d\n",dis[][n]);
  33. return ;
  34. }

【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了(很慢的)

  1. #include<bits/stdc++.h>
  2. const int maxn = ;
  3.  
  4. std::vector<int> f[maxn];
  5. int fa[maxn];
  6. int n,m,s;
  7. int vis[maxn];
  8.  
  9. int read()
  10. {
  11. char ch = getchar();
  12. int num = ;
  13. for (; !isdigit(ch); ch = getchar());
  14. for (; isdigit(ch); ch = getchar())
  15. num = (num<<)+(num<<)+ch-;
  16. return num;
  17. }
  18. void buildStructure(int now)
  19. {
  20. for (unsigned int i=; i<f[now].size(); i++)
  21. if (!fa[f[now][i]])
  22. {
  23. fa[f[now][i]] = now;
  24. buildStructure(f[now][i]);
  25. }
  26. }
  27. int main()
  28. {
  29. n = read(), m = read(), s = read();
  30. for (int i=; i<n; i++)
  31. {
  32. int x = read(), y = read();
  33. f[x].push_back(y), f[y].push_back(x);
  34. }
  35. fa[s] = s;
  36. buildStructure(s);
  37. fa[s] = ;
  38. for (int i=; i<=m; i++)
  39. {
  40. int x = read(), y = read();
  41. for (; x; x = fa[x]) vis[x] = i;
  42. for (; y; y = fa[y])
  43. if (vis[y] == i)
  44. break;
  45. printf("%d\n",y);
  46. }
  47. return ;
  48. }

当然以上做法是过不了这题的

倍增法

倍增的话,算是一种对于模拟法的优化吧。

我们每一次不止跳一步,而是以$2^i$步数向上跳。

那么就需要O(nlogn)预处理一些东西,查询则是O(logn)的。

参考:

1.【白话系列】最近公共祖先

2.LCA(离线Tarjan算法,在线倍增法)详解

3.LCA详解

4.题解 P3379 【【模板】最近公共祖先(LCA)】

  1. #include<bits/stdc++.h>
  2. const int maxn = ;
  3. const int logMaxn = ;
  4.  
  5. int n,m,s;
  6. int deep[maxn],p[maxn][logMaxn];
  7. std::vector<int> f[maxn];
  8.  
  9. inline int read()
  10. {
  11. char ch = getchar();
  12. int num = ;
  13. for (; !isdigit(ch); ch = getchar());
  14. for (; isdigit(ch); ch = getchar())
  15. num = (num<<)+(num<<)+ch-;
  16. return num;
  17. }
  18. void dfs(int now, int fa)          //递归预处理
  19. {
  20. deep[now] = deep[fa]+;
  21. p[now][] = fa;
  22. for (int i=; (<<i)<=deep[now]; i++)
  23. p[now][i] = p[p[now][i-]][i-];
  24. for (unsigned int i=; i<f[now].size(); i++)
  25. if (f[now][i]!=fa)
  26. dfs(f[now][i], now);
  27. }
  28. int lca(int x, int y)            //倍增LCA
  29. {
  30. if (deep[x] > deep[y]) std::swap(x, y);
  31. for (int i=logMaxn-; i>=; i--)
  32. if (deep[x]<=deep[y]-(<<i))
  33. y = p[y][i];
  34. if (x==y) return x;
  35. for (int i=logMaxn-; i>=; i--)
  36. if (p[x][i]==p[y][i])
  37. continue;
  38. else x = p[x][i], y = p[y][i];
  39. return p[x][];
  40. }
  41. int main()
  42. {
  43. n = read(), m = read(), s = read();
  44. register int i,x,y;
  45. for (i=; i<n; i++)
  46. {
  47. x = read(), y = read();
  48. f[x].push_back(y), f[y].push_back(x);
  49. }
  50. dfs(s, );
  51. for (i=; i<=m; i++)
  52. {
  53. x = read(), y = read();
  54. printf("%d\n",lca(x, y));
  55. }
  56. return ;
  57. }

【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【在更】的更多相关文章

  1. 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)

    洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...

  2. 倍增LCA学习笔记

    前言 ​ "倍增",作为一种二进制拆分思想,广泛用于各中算法,如\(ST\)表,求解\(LCA\)等等...今天,我们仅讨论用该思想来求解树上两个节点的\(LCA\)(最近公共祖先 ...

  3. [BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)

    4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2131  Solved: 865[Submit][Statu ...

  4. 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增

    倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...

  5. cogs 1588. [USACO Feb04]距离咨询 倍增LCA

    1588. [USACO Feb04]距离咨询 ★★   输入文件:dquery.in   输出文件:dquery.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 农夫 ...

  6. [板子]倍增LCA

    倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...

  7. 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]

    题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his b ...

  8. Gym100685G Gadget Hackwrench(倍增LCA)

    题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...

  9. Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

    题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_di ...

随机推荐

  1. Android的文件读取与存储

    Java新建文件,然后就可以写入数据了,但是Android却不一样,因为Android是 基于Linux的,我们在读写文件的时候,还需加上文件的操作模式 Environment类是一个提供访问环境变量 ...

  2. JPA-day04 核心API 一级缓存 主键生成策略 实体对象的4种状态 多对一关系 延迟加载

  3. struts2学习笔记 day01

  4. Requests 入门

    首先直接通过管理员运行cmd,然后执行 pip install requests  就可以直接安装Requests库了 有个最基本的语句 r = requests.get(url) 通过request ...

  5. STP-1-802.1D生成树协议及改进

    第一个 IEEE 标准化的STP也常称为“ 传统”STP,最初在802. 1D中进行了描述. 之后得到了改进,发布在所谓的修正案中:快速 STP( RSTP),在修正案802. 1w 中描述了它的标准 ...

  6. wawawa8的模板复习计划

    wawawa8的模板复习计划 数据结构 //手写堆 [link][https://www.luogu.org/problemnew/show/P3378] //并查集 [link][https://w ...

  7. python之 __getattr__、__getattr__、__getitem__、__setitem__ 使用

    python之 __getattr__.__getattr__.__getitem__.__setitem__ 使用 __getattr__内置使用点号获取实例属性属性如 s.name,自调用__ge ...

  8. oracle把一个表的数据复制到另一个表中

    http://blog.csdn.net/my_name_nb/article/details/64128015 ........................ 1. 新增一个表,通过另一个表的结构 ...

  9. python对文件的压缩解压

    python自带的zipfile的模块支持对文件的压缩和解压操作 zipfilp.ZipFile 表示创建一个zip对象 zipfile.ZipFile(file[, mode[, compressi ...

  10. 搭建高可用mongodb集群(一)——mongodb配置主从模式

    转载自:LANCEYAN.COM 在大数据的时代,传统的关系型数据库要能更高的服务必须要解决高并发读写.海量数据高效存储.高可扩展性和高可用性这些难题.不过就是因为这些问题Nosql诞生了. NOSQ ...