原题链接:
http://acm.split.hdu.edu.cn/showproblem.php?pid=5857
(可能会失效)
题意:
给你一个升序的数列,查询两个区间合并之后的数列里的中位数
分析:
看到100000,就会以为是线段树。其实显然没有充分利用已经升序这个特性,仔细考虑其实就是一道模拟题。
乍一看,会有三种情况:
1、两段区间分离
2、两段区间相交
3、一段区间包含另一段区间
(然后还会突然想到,两个区间以一定是前后再前,细思恐极,可怕的模拟题)
其实很多情况可以通过一定的合并变成另一种状态:
1、两区间先后在前,可以通过左端点互换和右端点互换,变成先前再后。
2、区间包含可以通过右端点互换,使之变为区间相交。
最终得出结论,只有两种情况:分离和相交。
还有一些注意的是合并之后新数列的长度的奇偶,因为怕出错,所以直接分类讨论,没有做过多的转化和代码缩减、
在区间相交的情况下,会产生3段区间,中间的区间是重复区间
在重复区间中,必然存在两个两个连在一起吗,所以只要
在相交的情况下,中间一段因为是重复的。只需要先求出在重复区间去重的情况下是第几个就行了,
然后除以2,向上取整。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn=100010; 9 long long num[maxn]; 10 11 int main() { 12 int t; 13 scanf("%d",&t); 14 while(t--) { 15 int n,m; 16 scanf("%d%d",&n,&m); 17 for(int i=1; i<=n; i++) { 18 scanf("%I64d",&num[i]); 19 } 20 for(int i=0; i<m; i++) { 21 double ans=0; 22 int l1,r1,l2,r2; 23 scanf("%d%d%d%d",&l1,&r1,&l2,&r2); 24 if(l1>l2||(l1==l2&&r1>r2)) { 25 swap(l1,l2); 26 swap(r1,r2); 27 } 28 if(l1<=l2&&r1>=r2) { 29 swap(r1,r2);//区间包含转化为区间相交 30 } 31 int len1=r1-l1+1; 32 int len2=r2-l2+1; 33 int len=len1+len2; 34 if(r1<l2) {//两区间分离 35 if(len%2==0) { 36 int half=len/2; 37 if(len1>half) { 38 ans=double(num[l1+half-1]+num[l1+half])/2; 39 } else if(len2>half) { 40 ans=double(num[r2-half+1]+num[r2-half])/2; 41 } else if(len1==half) { 42 ans=double(num[r1]+num[l2])/2; 43 } 44 } else { 45 int half=len/2+1; 46 if(len1>=half) { 47 ans=double(num[l1+half-1]); 48 } else { 49 ans=double(num[r2-half+1]); 50 } 51 } 52 } else {//两区间相交 53 if(len%2==0) { 54 int half=len/2; 55 if(l1+half-1<l2) { 56 ans=double(num[l1+half-1]+num[l1+half])/2; 57 } else if(r2-half+1>r1) { 58 ans=double(num[r2-half+1]+num[r2-half])/2; 59 } else { 60 half=half-(l2-l1); 61 ans=double(num[l2+(int)ceil(double(half)/2)-1]+num[l2+(int)ceil(double(half+1)/2)-1])/2;// 62 } 63 } else { 64 int half=len/2+1; 65 if(l1+half-1<l2) { 66 ans=double(num[l1+half-1]); 67 } else if(r2-half+1>r1) { 68 ans=double(num[r2-half+1]); 69 } else { 70 half=half-(l2-l1); 71 ans=double(num[l2+(int)ceil(double(half)/2)-1]); 72 } 73 } 74 } 75 printf("%.1f ",ans); 76 } 77 } 78 return 0; 79 }