Problem A 中间值

对于$2$个非严格单增序列$\{A_n\} , \{B_n\}$,维护下列两个操作:

1 x y z: (x=0)时将$A_y = z$ , (x=1)时将$B_y = z$

2 l1 r1 l2 r2 : 输出$A[l1] - A[r1]$和$B[l2] - B[r2]$ 这些数中的中位数,保证总数为奇数。

对于$100\%$的数据满足 $1 \leq n \leq 5\times 10^5 ,1 \leq m\leq 10^6$

Solution: 有一种简单实现$O(n log_2 n)$的方法:

  我们有两个非严格单增的数组$a[]$和$b[]$设$|a| < |b|$ ,现在要求第$k$小数。

  我们在$a[]$数组中求出$min(k/2,|a|)$的位置的数$a[i]$ ,同时在$b[]$数组中找出$|b|-i$位置的数$b[j]$

   判断$a[i]$ 和$b[j]$的大小,如果$a[i] > b[j]$ 说明$b[1] .. b[j]$都不可能是排名第$k$的数,

  否则,$a[1] ... a[i]$都不可能是排名第$k$的数。

  每一次,k都可以变成一半,所以复杂度就是$log_2 n $ 每次查询。

  总复杂度就是$O(n \ log_2 \ n )$

# include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;

int query(int a[],int len1,int b[],int len2,int k)
{
    if (len1 > len2) return query(b,len2,a,len1,k);
    if (len1 == 0) return b[k];
    if (k==1) return min(a[1],b[1]);
    int ka = min(k/2,len1) , kb=k-ka;
    if (a[ka] < b[kb]) return query(a+ka,len1-ka,b,len2,k-ka);
    else return query(a,len1,b+kb,len2-kb,k-kb);
}
int a[N],b[N],n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) scanf("%d",&b[i]);
    while (m--) {
        int op; scanf("%d",&op);
        if (op==1) {
            int x,y; scanf("%d%d%d",&op,&x,&y);
            if (op==0) a[x]=y; else b[x]=y; 
        } else {
            int l1,r1,l2,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            printf("%d\n",query(a+l1-1,r1-l1+1,b+l2-1,r2-l2+1,(r2-l2+1+r1-l1+1)/2+1));
        }
    }
    return 0;
}
A.cpp

相关文章:

  • 2021-06-09
  • 2021-09-30
  • 2021-07-06
  • 2021-09-11
  • 2021-05-19
  • 2021-08-01
  • 2021-06-08
  • 2022-03-08
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案