zoukankan      html  css  js  c++  java
  • jQuery火箭图标返回顶部代码

    关于倍增

    学习博客

    前几天(lyk)给我们讲了倍增但是(emmmm)他说话声音也太小了,坐在后排根本听不清楚诶,前边一群大佬还在叽叽喳喳的说话,上课效率低得一批。

    [color{purple}{我太难了} ]

    顾名思义倍增就是倍增,用(dsr)大佬的话来说就是(wuwu)腻。

    我们有一个数组(f[i][j])表示从(i)开始的长度为(2^j)的区间即区间([i,i+2^j])

    递推公式:

    预处理ST表
    (f[i][j]=max(f[i][j-1]),f[i+2^{j-1}][j-1])
    说句闲话
    为什么这么写?我之前第一遍自己学的时候,看其他人的博客,有的直接不解释,有的说自己揣摩(qwq),我就是揣摩不出来才去看您的(blog)的哇。
    后来(lyk)讲课问谁没听懂,偌大的教室里,只有我的小短手在教室后边高高的自信的举起,再不会就对不起(lyk)的一对一辅导了.

    灵魂画师又要入场了

    多么清晰~多么明了~博主已飘

    for(int i = 1; i <= m; i++) f[i][0] = read();//自己到自己这个区间
    for(int j = 1; j <= log(m); j++)
    	for(int i = 1; i + (1 << j) <= m; i++)
    		f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); 
    

    j的循环范围

    这里说一下为什么循环外层是(j)
    再说一句闲话:
    (wtf)?刚刚我在画图,阿龙过来来了一句:“你又待聂画画,打草纸组啥,光待聂画画。”嗯??你告诉我往草纸上画咋粘博客里。双面胶?来来来,舞台留给你,请开始你的表演。于是乎,(lkx)大佬帮我画了张图

    回归正题,咱们看图说话并没有什么用的图假设我们先枚举(i)那么我们的枚举顺序就是([1,1],[1,2]......[1,m])当我们更新到([1,2])时,就要用到([1,1])([2,2])这两个点,但是由于我们的外层循环是(i)此时的([2,2])还没有值,所以这样更新出来的就是错的。

    查询:

    把我们需要查询的区间([l,r])分成两段([l,2^k])([r-2^k+1,r])其中这个(k)(2^k leq r-l+1)的所有数中的最大的数,就算这两部分互相覆盖由于他们是取最值,所以对答案没有影响
    (f[l][r]=max(f[l][k],f[r-(1<<k)+1][k]))
    为什么左端点是(r-2^k+1)可能只有我这样的才会问了好久才明白
    简单一点我们设(L)为他的左端点,因为是一个闭区间且已知区间长度及区间右端点,可得方程(r-L+1=2^k)解得L即为左端点

    倍增其实还有个很常用的应用:

    求LCA!

    此时设(f[i][j])表示从节点(i)向上跳(2^j)个节点
    (f[i][j]=f[f[i][j-1]][j-1])

    void work(int x, int fa) {
    	f[x][0] = fa;
    	dep[x] = dep[fa] + 1;
    	for(int i = 1; i < 20; i++) 
    		f[x][i] = f[f[x][i - 1]][i - 1];
    }
    void dfs(int x, int fa) {
    	work(x, fa);
    	for(int i = head[x]; i; i = e[i].nxt) 
    		if(e[i].to != fa) work(e[i].to, x);
    }
    

    (dfs)的过程中更新
    一种优化常数的方法:先处理出(lg)数组,表示以(2)为底(i)的对数

    for(int i = 2; i <= n; i++)
    	lg[i] = lg[i >> 1] + 1;
    
    查询:

    先使两个待查询的点跳到同一深度,然后再从(i)开始枚举,逼近他们的LCA,最后一定会是在他们的LCA的下一层,最后直接输出当前节点的爸爸也就是(f[i][0])

    	if(dep[a] < dep[b]) swap(a, b);
    	for(int i = 20; i >= 0; i--) 
    		if(dep[f[a][i]] >= dep[b])
    			a = f[a][i];//跳到同一深度 
    	if(a == b) return a;//或者是b反正他俩都一样
    	for(int i = 20; i >= 0; i--)
    		if(f[a][i] != f[b][i])
    			a = f[a][i], b = f[b][i];//同时跳 
    	return f[a][0]; 
    }
    

    (qwq)貌似是有(O(1))的的查询的喂

    我:“(lyk),我(O(1))查询的不会”
    大佬:“(hai xie),不用会这锅啊,,谁写这(hu)滴啊”

    路径最小权值

    我们设(w[i][j])表示从节点(i)向上跳(2^j)个节点内所经过的最小的权值

    for(int j = 1; j < 20; j++)
    	for(int i = 1; i + (1 << j) - 1 <= tot; i++)
    		w[i][j] = min(w[i][j - 1], w[f[i][j - 1]][j - 1]);
    //f[i][j]是预先处理处的代表i号点向上跳2^j步之后跳到的节点 
    

    历时一上午多点我总算把这篇文章磨完了........

    谢谢收看, 祝身体健康!

  • 相关阅读:
    防御式编程
    Linux磁盘与文件系统管理
    更加抽象
    高质量的子程序
    Linux文件与目录管理
    抽象
    可以工作的类
    Linux的文件权限与目录配置
    条件、循环和其他语句
    软件构建中的设计
  • 原文地址:https://www.cnblogs.com/yanxiujie/p/11758674.html
Copyright © 2011-2022 走看看