二分,倍增的一些思考(lost my music:可持久化栈)

浅谈二分

来自8,17考试模拟24。

本题:

单调凸包。(找凸包方向:联系高考数学线性规划)

弹栈操作是一个个向后弹的。
序列转换为树上。
对于树上结构,只需记录父子关系,即可还原出一整棵树。
因为要可持久化,那么这里的栈也变为了树状。
只需记录在栈里的父亲即可。
甚至不用开一个数组作为栈。
由于单调性,搭配倍增使用,效果更佳。

二分,倍增的一些思考:

浅谈二分,倍增
1、那么普通的数组类型栈由于单调性,且是序列上的连续,可以用二分和倍增快速pop
    (这里的二分指l,r,while循环,check(mid) 的二分)
    2、既然既可以使用二分,也可以使用倍增,那他们的区别在哪儿?
    发现:倍增是学lca时学到的,是用来解决树上问题。可以说他满足单调性,但由于树的特殊性质,无法用二分解决。
    因此出现了倍增数组。良好地解决了树上二分祖先的问题。
    推论:倍增数组也可以用在比树更简单的序列上。他是二分的强化版。
    则二分能解决的问题倍增大多可以解决。
    而大多情况下使用mid二分(也可倍增二进制拆分),是因为直接mid,不是固定log,可能会少一点。
    而倍增i=20~0是二进制拆分,复杂度固定log,与二分上限相同,随机情况下会慢一点点。
    不需要记录一些关系时,倍增的二进制拆分和二分是差不多的。
    但是倍增数组提供了很多灵活而多样的功能,使他比单纯二分的适应性、功能性更强。
    
    附:普通二分的倍增写法:(相比麻烦一点)(但是很帅啊)
    int l,r;
    for(int i,20,0){
        if(check(r-(1<<i)))r=(r-(1<<i))
        else l=(r-(1<<i))-1
    }
  本题代码:

#include<bits/stdc++.h>
#define F(i,a,b) for(rg int i=a;i<=b;++i)
#define il inline
#define rg register
#define LL long long
#define pf(a) printf("%d ",a)
#define phn puts("")
using namespace std;
int read();
/*
弹栈操作是一个个向后弹的。
序列转换为树上。
对于树上结构,只需记录父子关系,即可还原出一整棵树。
因为要可持久化,那么这里的栈也变为了树状。
只需记录在栈里的父亲即可。
甚至不用开一个数组作为栈。
由于单调性,搭配倍增使用,效果更佳。

另:1、那么普通的数组类型栈由于单调性,且是序列上的连续,可以用二分和倍增快速pop
    (这里的二分指l,r,while循环,check(mid) 的二分)
    2、既然既可以使用二分,也可以使用倍增,那他们的区别在哪儿?
    发现:倍增是学lca时学到的,是用来解决树上问题。可以说他满足单调性,但由于树的特殊性质,无法用二分解决。
    因此出现了倍增数组。良好地解决了树上二分祖先的问题。
    推论:倍增数组也可以用在比树更简单的序列上。他是二分的强化版。
    则二分能解决的问题倍增大多可以解决。
    而大多情况下使用mid二分(也可倍增二进制拆分),是因为直接mid,不是固定log,可能会少一点。
    而倍增i=20~0是二进制拆分,复杂度固定log,与二分上限相同,随机情况下会慢一点点。
    不需要记录一些关系时,倍增的二进制拆分和二分是差不多的。
    但是倍增数组提供了很多灵活而多样的功能,使他比单纯二分的适应性、功能性更强。

    附:普通二分的倍增写法:
    int l,r;
    for(int i,20,0){
        if(check(r-(1<<i)))r=(r-(1<<i))
        else l=(r-(1<<i))-1
    }

*/
#define N 500010
int n;
il double min(const double &x,const double &y){return x<y?x:y;}
int f[N];LL c[N];
vector<int>son[N];//要记录1、凸壳倍增祖先。
int las[N<<1][20+2];LL dep[N];
int jud(int k,int j,int i){return (c[i]-c[j])*(dep[j]-dep[k])<=(c[j]-c[k])*(dep[i]-dep[j]);}
void dfs(int x){
    dep[x]=dep[f[x]]+1;
    int p=f[x];
    for(int i=20;i>=0;--i){
        if(las[p][i]<2)continue;
        int t=las[p][i];
        if(jud(las[t][0],t,x))p=t;
    }
    if(p!=1){
        if(jud(las[p][0],p,x))p=las[p][0];
        /*
            找凸包切线:类似于lca抬根。
            要找凸包中最靠前一个不符合条件的点。
            然后去判断他的父节点是否符合条件。
            因为如果倍增跳过了,会一直斜率(i,j)>(j,k)。
            所以要找最后一个(i,j)<=(j,k)的点。
            然后判断他的父节点是否符合。
            凸包对于1要特判。
        */
    }
    las[x][0]=p;
    F(i,1,20)las[x][i]=las[las[x][i-1]][i-1];
    int ting=son[x].size()-1;
    F(i,0,ting){
        dfs(son[x][i]);
    }
}
int main(){
    n=read();
    F(i,1,n)c[i]=read();
    F(i,2,n)f[i]=read(),son[f[i]].push_back(i);
    dfs(1);
    F(i,2,n){
        printf("%.10lf\n",(double)(c[las[i][0]]-c[i])/(dep[i]-dep[las[i][0]]));
    }
}
il int read(){
    int s=0,f=0;char ch;
    while(ch=getchar(),f+=(ch==‘-‘),!isdigit(ch));
    for(;isdigit(ch);s=s*10+(ch^48),ch=getchar());
    return f?-s:s;
}
/*
g++ 3.cpp -g
./a.out
8
31516 11930 18726 12481 79550 63015 64275 7608
1 1 2 4 2 4 5

*/

原文地址:https://www.cnblogs.com/seamtn/p/11370324.html

时间: 2024-11-01 09:26:17

二分,倍增的一些思考(lost my music:可持久化栈)的相关文章

【bzoj2280】[Poi2011]Plot 二分+倍增+二分+最小圆覆盖

题目描述 给出一系列点p_1, p_2, ... , p_n,将其分成不多余m个连续的段,第i段内求一个点q_i,使得q_i到这段内点的距离的最大值的最大值最小 输入 第一行,n m下面n行,每行两个整数,表示p_i的x y坐标1<=m<=n<=100000坐标范围[-1000000,1000000] 0<p,q,r<=150,输入中至少包含一个’N’ 输出 第一行,q_i到这段内点的距离的最大值的最大值的最小值第二行,分成的段数k下面k行,每行两个实数,表示q_k的x y坐

题解——dinner(二分+倍增)

题解--dinner(二分+倍增) 见ssw02的:题解--慕斯蛋糕 好像这道题 二分+二分+贪心 也可以.(日后更,T3还没改) 如有不足,请大佬指出 原文地址:https://www.cnblogs.com/ssw02/p/11394142.html

习题:疫情控制(二分+倍增+贪心)

noip2012疫情控制 描述H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的. 现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队.一支军队可以在有道路连接的城市间移动,

二分查找之再思考

一.一般的二分查找 一般的二分查找即,输出要查找元素在数组中的位置,这里的位置没有特殊限定,没有要求是数字第一次出现的位置,也没有要求是最后一次出现的位置. int getPos(vector<int> A, int n, int val) { if (A.size()==0) { return NULL; } int low=0; int high=n-1; while(low<=high) //注意这里是小于等于 { if (A[(low+high)/2]>val) { hig

二分算法的一些思考

二分算法的思想: 通过不断减小问题规模,从边界条件出发求解问题.(通常是单调性问题,判定形式较为简单) 二分算法的优点: 1.把n的时间复杂度优化到logn 2.将一个问题转化为判定性质问题求解 代码: while(l<=r) { if(check(mid) { ans = mid; r = mid-1; } else ans = mid+1; } 例题: block towers n个人选择n个不同2的倍数的数,m个人选择m个3的倍数的数,选择的最大数字最小!

有关二分查找的边界思考

1.二分查找概念 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表.重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功.

【BZOJ1901】Dynamic Rankings [整体二分]

Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序

bzoj2144 跳跳棋 二分

[bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. Input 第一行包含三个整数,表示当前棋子的

二分搜索树(Binary Search Tree)

目录 什么是二叉树? 什么是二分搜索树? 二分搜索树的基本操作 二分搜索树添加新元素 二分搜索树的遍历(包含非递归实现) 删除二分搜索树中的元素 什么是二叉树? ??在实现二分搜索树之前,我们先思考一下,为什么要有树这种数据结构呢?我们通过企业的组织机构.文件存储.数据库索引等这些常见的应用会发现,将数据使用树结构存储后,会出奇的高效,树结构本身是一种天然的组织结构.常见的树结构有:二分搜索树.平衡二叉树(常见的平衡二叉树有AVL和红黑树).堆.并查集.线段树.Trie等.Trie又叫字典树或前