整体二分

本文介绍了一种在处理大量询问时优化二分搜索的方法——整体二分,通过避免重复计算来提升效率。适用于需要多次查询同一数据集的问题,如矩阵乘法等。文章通过具体的代码示例展示了整体二分的应用。

相对于普通二分,整体二分用于处理较多询问.如果用普通二分去处理询问,效率将是O(Q*log×f(?))多出来的Q将无法让人承受。因而有了整体二分。整体二分与二分的最大区别就是对所有询问一同处理。所谓的一同处理,是指省去了二分中的冗余部分,上一个询问二分过这个区间,而当前询问又二分了一次,整体二分保证了没有这个冗余。

具体而言,当前带着所有询问传到了一个区间,整理得到一部分询问满足左区间,另一部分满足右区间(废话。。),那么把它们推入两个队列,搞进左右区间继续二分即可。这样就剪掉了时间效率中的Q,使得大量重复的二分被合并。

至于带修改的,明天填坑。
举个很著名的例子:查找区间K大,当然可以用主席树,但有的题并不行。
比如:矩阵乘法.(板子在此OwO)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#define N 505
using namespace std;
int n,m,tot,T,zhan[N*600],mark[N*600],ans[N*600],id[N*600],t[N][N];
struct node{int x,y,h;}a[N*N];
struct QQQ{int l1,l2,r1,r2,k;}q[N*600];
void add(int x,int y,int k)
{
    for(int i=x;i<=n;i+=i&-i)
        for(int j=y;j<=n;j+=j&-j)
            t[i][j]+=k;
}
int q1(int x,int y)
{
    int s=0;
    for(int i=x;i>0;i-=i&-i)
        for(int j=y;j>0;j-=j&-j)
            s+=t[i][j];
    return s;
}
int Q(int k)
{
    int l1=q[k].l1,l2=q[k].l2,r1=q[k].r1,r2=q[k].r2;
    return q1(l2,r2)+q1(l1-1,r1-1)-q1(l1-1,r2)-q1(l2,r1-1);
}//套二维树状数组
inline bool cmp(node a,node b){return a.h<b.h;}
void work(int l,int r,int L,int R)
{
    if(L==R||l>r)return;
    int mid=L+R>>1;
    while(a[T+1].h<=mid&&T<tot){add(a[T+1].x,a[T+1].y,1);T++;}
    while(a[T].h>mid){add(a[T].x,a[T].y,-1);T--;}
    int sum=0;
    for(int i=l;i<=r;i++)
    {
        if(Q(id[i])>q[id[i]].k-1)
        {
            mark[i]=1;ans[id[i]]=mid;sum++;
        }
        else mark[i]=0;
    }
    int l1=l,l2=l+sum;
    for(int i=l;i<=r;i++)
        if(mark[i])zhan[l1++]=id[i];
        else zhan[l2++]=id[i];
    for(int i=l;i<=r;i++)id[i]=zhan[i];
    work(l,l1-1,L,mid);work(l1,l2-1,mid+1,R);
}

int main()
{
    scanf("%d%d",&n,&m);int mm=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[++tot].h);
            a[tot].x=i;a[tot].y=j;
            mm=max(mm,a[tot].h);
        }
    sort(a+1,a+tot+1,cmp);
    for(int i=1;i<=m;i++)scanf("%d%d%d%d%d",&q[i].l1,&q[i].r1,&q[i].l2,&q[i].r2,&q[i].k);
    for(int i=1;i<=m;i++)id[i]=i;
    work(1,m,0,mm+1);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}
<think> 首先,用户的问题是“洛谷整体二分入门题”,这似乎是中文的。我需要使用中文回答问题。 主题是“洛谷整体二分入门题”。洛谷是一个在线编程平台,整体二分是一种算法技术,可能指的是整体二分查找或类似的东西。在算法竞赛中,整体二分(有时称为“整体二分法”或“整体二分搜索”)常用于解决多查询问题,比如处理多个查询同时进行二分搜索。 用户提到了“入门题”,意思是入门级别的题目。所以,我应该解释整体二分的基本概念,并提供一个简单的例子或代码实现。 回顾系统提示:我必须在回答完问题后,根据用户的问题和我的回答,提出3-5个相关问题。这些问题必须以“§§相关问题§§”开头,并且在回答的末尾输出。第一行必须是完整的“§§相关问题§§”,不能换行分散。 示例格式显示了一个关于快速排序的回答,然后列出了相关问题。 所以,针对这个问题,我需要: 1. **回答问题**:解释整体二分是什么,提供一个简单的入门题例子,并用代码实现(可能是Python,因为示例中是Python)。 2. **提出相关问题**:基于我的回答,生成3-5个相关问题。 关键点: - **整体二分**:它是一种用于处理多个查询的二分搜索算法优化。例如,在一个有序数组中查找多个元素的位置时,可以一次性处理所有查询,而不是一个个二分搜索,从而减少时间复杂度。 - **入门题**:洛谷上可能有相关题目,比如经典的“查找数组中多个元素的位置”或类似问题。 一个常见的整体二分入门题是“静态区间第k小数”或类似问题。但为了简单,我可以选择一个基础例子。 假设一个简单例子:有一个排序数组,和多个查询,每个查询要求查找一个值的索引。使用整体二分来高效处理。 代码实现:由于示例是Python,我应该用Python写一个简单的整体二分实现。 结构化我的回答: 1. **解释整体二分**:简要描述它是什么和为什么有用。 2. **提供一个例子**:描述一个简单的场景。 3. **给出代码**:实现整体二分算法。 4. **结束回答**。 然后,输出“§§相关问题§§”,后跟3-5个相关问题。 相关问题必须基于用户的问题和我的回答。例如: - 什么是整体二分的时间复杂度? - 整体二分在哪些场景下使用? - 如何扩展整体二分到动态查询? - 洛谷上还有哪些整体二分的题目? 确保问题是中文的。 现在,构建回答: **回答部分:** 整体二分(或称整体二分搜索)是一种高效处理多个二分查找查询的算法。它将所有查询同时处理,通过递归地将查询和数组分割,直到所有查询被解决。常用于算法竞赛中,如查找静态数组中多个值的位置。 一个入门题例子:给定一个排序数组arr和一个查询列表queries,每个查询是一个值,要求返回该值在arr中的索引(如果存在),否则返回-1。使用整体二分实现。 Python代码实现: ```python def binary_search_all(arr, queries): # 假设arr是排序好的数组 # queries是一个列表,每个元素是一个查询值 # 返回一个列表,对应每个查询的索引 # 先创建一个结果数组,初始化为-1 result = [-1] * len(queries) # 辅助函数,递归处理查询 def helper(low, high, query_indices): if low > high or not query_indices: return mid = (low + high) // 2 mid_val = arr[mid] # 分割查询索引:小于、等于、大于mid_val left_indices = [] mid_indices = [] right_indices = [] for idx in query_indices: q = queries[idx] if q < mid_val: left_indices.append(idx) elif q == mid_val: result[idx] = mid # 找到匹配 else: # q > mid_val right_indices.append(idx) # 递归处理左半部分和右半部分 helper(low, mid-1, left_indices) helper(mid+1, high, right_indices) # 初始调用,所有查询索引 query_indices = list(range(len(queries))) helper(0, len(arr)-1, query_indices) return result # 示例使用 arr = [1, 3, 5, 7, 9] queries = [5, 2, 9] print(binary_search_all(arr, queries)) # 应输出 [2, -1, 4] ``` 这个代码实现了整体二分,递归地将查询分配到左、中、右部分。当查询值等于当前中点时,直接设置结果。 **相关问题部分:** 必须以“§§相关问题§§”开头,然后列出3-5个问题。例如: 1. 整体二分的时间复杂度是多少? 2. 整体二分与普通二分搜索有什么区别? 3. 在洛谷上,有哪些推荐的整体二分入门题目? 4. 整体二分如何处理重复元素? 5. 如何优化整体二分的空间复杂度? 确保输出格式正确:第一行是“§§相关问题§§”,然后直接列出问题,用数字点号。 最终输出: [回答内容] §§相关问题§§ 1. ··· 2. ··· 3. ··· 现在,整合起来。 </think> 整体二分(又称整体二分搜索)是一种用于高效处理多个二分查找查询的算法优化技术。它将所有查询同时处理,通过递归地将查询和数组分割成子问题,从而减少重复计算,时间复杂度通常为O((n + q) log n),其中n是数组大小,q是查询数。整体二分常用于算法竞赛中解决静态数组中的多查询问题,如查找多个值的位置或统计查询。 在洛谷(Luogu)上,一个典型的入门题是“查找排序数组中多个值的索引”。例如,题目描述:给定一个排序数组arr和一个查询列表queries,每个查询是一个值,要求返回该值在arr中的索引(如果存在),否则返回-1。使用整体二分实现此功能。 下面是一个Python代码实现示例。该代码递归地将查询分配到左、中、右部分,当查询值等于当前中点时直接设置结果: ```python def binary_search_all(arr, queries): # 初始化结果数组,为每个查询预留默认值-1 result = [-1] * len(queries) # 递归辅助函数,处理从low到high的区间和查询索引列表 def helper(low, high, query_indices): if low > high or not query_indices: return mid = (low + high) // 2 mid_val = arr[mid] # 分割查询索引:根据与mid_val的比较 left_indices = [] # 小于mid_val的查询 mid_indices = [] # 等于mid_val的查询(直接处理) right_indices = [] # 大于mid_val的查询 for idx in query_indices: q = queries[idx] if q < mid_val: left_indices.append(idx) elif q == mid_val: result[idx] = mid # 找到匹配,设置索引 else: # q > mid_val right_indices.append(idx) # 递归处理左半部和右半部 helper(low, mid - 1, left_indices) helper(mid + 1, high, right_indices) # 初始调用:覆盖整个数组和所有查询索引 helper(0, len(arr) - 1, list(range(len(queries)))) return result # 示例测试 if __name__ == "__main__": arr = [1, 3, 5, 7, 9] # 排序数组 queries = [5, 2, 9] # 查询列表 print(binary_search_all(arr, queries)) # 输出:[2, -1, 4](索引从0开始) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值