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; }