[分治]JZOJ 6308 中间值

Description

 

Input

Output

 

Sample Input

5 5
12 41 46 68 69
35 61 82 84 96
2 1 4 3 5
1 0 5 75
2 2 4 3 4
2 3 4 1 5
2 1 4 2 4
 

Sample Output

68
68
68
61
 

Data Constraint

分析

这题相信都能注意到两数列保证一直单调上升

最开始写的是倍增然后upper_bound判断,显然两个log会T

然后题解做法好神仙

将要询问的k折半,在两个区间中找到对应的位置,然后比较一下大小,显然较小的那部分可以直接舍去,然后把区间左端往右拉,k减去舍去的部分,这就保证了log的复杂度

而且普适性很强,只要是单调两区间求第k大都能写的嗷

就是细节多了点(改了半天发现输出没有判断相等的情况,这都给了30pt)

 

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=5e5+10;
int n,m;
int a[N],b[N];

void Solve(int l1,int r1,int l2,int r2,int k) {
    if (k==1) {
        if (l1<=r1&&(l2>r2||a[l1]<b[l2])) printf("%d\n",a[l1]);
        if (l2<=r2&&(l1>r1||a[l1]>=b[l2])) printf("%d\n",b[l2]);
        return;
    }
    int s,t,p=k>>1;
    if (l1+p-1>=r1) s=r1,t=max(l2+(k-(r1-l1+1))-2,l2);
    else if (l2+(k-p)-1>=r2) t=r2,s=max(l1+(k-(r2-l2+1))-2,l1);
    else s=max(l1+p-1,l1),t=max(l2+(k-p)-1,l2);
    if (l1<=r1&&(l2>r2||a[s]<b[t])) Solve(s+1,r1,l2,r2,k-(s-l1+1));
    if (l2<=r2&&(l1>r1||a[s]>=b[t])) Solve(l1,r1,t+1,r2,k-(t-l2+1));
}

int main() {
    freopen("median.in","r",stdin);
    freopen("median.out","w",stdout);
    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]);
    for (int i=1,opt;i<=m;i++) {
        scanf("%d",&opt);
        if (opt==1) {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            if (x) b[y]=z; else a[y]=z;
        }
        else {
            int l1,r1,l2,r2,cnt=0,sum;
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            Solve(l1,r1,l2,r2,((r1-l1+r2-l2+2)>>1)+1);
        }
    }
}
View Code

 

posted @ 2019-08-19 07:56  Vagari  阅读(149)  评论(0编辑  收藏  举报