[分治]JZOJ 6308 中间值
分析
这题相信都能注意到两数列保证一直单调上升
最开始写的是倍增然后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); } } }
在日渐沉没的世界里,我发现了你。