山东第四届省赛: Boring Counting 线段树
http://acm.sdibt.edu.cn/JudgeOnline/problem.php?id=3237
Problem H:Boring Counting
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 6 Solved: 2
[Submit][Status][Discuss]
Description
In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence. Now you task is to answer a list of queries, for each query, please tell us among [L, R], how many Pi is not less than A and not greater than B( L<= i <= R). In other words, your task is to count the number of Pi (L <= i <= R, A <= Pi <= B).
Input
In the first line there is an integer T (1 < T <= 50), indicates the number of test cases.
For each case, the first line contains two numbers N and M (1 <= N, M <= 50000), the size of sequence P, the number of queries. The second line contains N numbers Pi(1 <= Pi <= 10^9), the number sequence P. Then there are M lines, each line contains four number L, R, A, B(1 <= L, R <= n, 1 <= A, B <= 10^9)
Output
For each case, at first output a line ‘Case #c:’, c is the case number start from 1. Then for each query output a line contains the answer.
Sample Input
1 13 5 6 9 5 2 3 6 8 7 3 2 5 1 4 1 13 1 10 1 13 3 6 3 6 3 6 2 8 2 8 1 9 1 9
Sample Output
Case #1: 13 7 3 6 9
HINT
Source
比赛的时候,没有头绪,今天别人说起划分树,想了一下,还真是可以做的。
但是要一点变形,这样的变形,让我已经看不清 划分树的影子了。
划分树----求区间第K 小/大 值
这道题是求区间求区间[l,r]中 满足 A<=xi<=B; xi属于[l,r]。求xi的个数。
如何转化的呢?
枚举区间第k小数==A。此时能求出一个值 hxl
枚举区间第K小数==B,此时得到一个值 tom
显然满足tom>=hxl。
那在这范围的数,是不是就满足了 A<=xi<=B !~~
这么一说,其实好简单。为什么没有想到呢? 划分树做的时候是求 第 k 小的是什么什么数字,现在换了回来而已,
求的是某个数字是区间里面第几小。
其实有个问题就又来了,A,B在区间[l,r]未必存在,这该怎么办?????
其实上面的说法,不严谨,(求的是某个数字是区间里面第几小。)应该说是求A的下届,B的上届值。
二分枚举,平均的时间会更小。在求下届和上届的过程中也要注意一些细节的问题、
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstring> 6 #define N 100010 7 using namespace std; 8 9 int toleft[30][N]; 10 int Tree[30][N]; 11 int Sort[N]; 12 13 14 15 void build(int l,int r,int dep) 16 { 17 int mid=(l+r)/2,sum=mid-l+1,lpos,rpos,i; 18 if(l==r) return ; 19 for(i=l;i<=r;i++) 20 if(Tree[dep][i]<Sort[mid]) sum--; 21 lpos=l; 22 rpos=mid+1; 23 for(i=l;i<=r;i++) 24 { 25 if(Tree[dep][i]<Sort[mid]) 26 { 27 Tree[dep+1][lpos++]=Tree[dep][i]; 28 } 29 else if(Tree[dep][i]==Sort[mid] && sum>0) 30 { 31 Tree[dep+1][lpos++]=Tree[dep][i]; 32 sum--; 33 } 34 else 35 { 36 Tree[dep+1][rpos++]=Tree[dep][i]; 37 } 38 toleft[dep][i]=toleft[dep][l-1]+lpos-l; 39 } 40 build(l,mid,dep+1); 41 build(mid+1,r,dep+1); 42 } 43 44 int query(int L,int R,int l,int r,int dep,int k) 45 { 46 int mid=(L+R)/2,newl,newr,cur; 47 if(l==r) return Tree[dep][l]; 48 cur=toleft[dep][r]-toleft[dep][l-1]; 49 if(cur>=k) 50 { 51 newl=L+toleft[dep][l-1]-toleft[dep][L-1]; 52 newr=newl+cur-1; 53 return query(L,mid,newl,newr,dep+1,k); 54 } 55 else 56 { 57 newr=r+(toleft[dep][R]-toleft[dep][r]); 58 newl=newr-(r-l-cur); 59 return query(mid+1,R,newl,newr,dep+1,k-cur); 60 } 61 } 62 int EF1(int l,int r,int num,int n) //枚举下届 63 { 64 int low=1,right=r-l+1,mid,tmp; 65 mid=(low+right)/2; 66 while(low<right) 67 { 68 tmp=query(1,n,l,r,0,mid); 69 if(tmp>=num) 70 right=mid-1; 71 else low=mid; //!!!! 72 mid=(low+right+1)/2; //!!! 加了一个1。 73 } 74 return low; 75 76 } 77 78 int EF2(int l,int r,int num,int n) 79 { 80 int low=1,right=r-l+1,mid,tmp; 81 mid=(low+right)/2; 82 while(low<right) 83 { 84 tmp=query(1,n,l,r,0,mid); 85 if(tmp>num) 86 right=mid; //!!! 87 else low=mid+1; 88 mid=(low+right)/2; //木有加1 89 } 90 return low; 91 } 92 93 int main() 94 { 95 int T,n,m,i,l,r,k,a,b,hxl,tom,qq; 96 scanf("%d",&T); 97 { 98 for(qq=1;qq<=T;qq++) 99 { 100 scanf("%d%d",&n,&m); 101 memset(Tree,0,sizeof(Tree)); 102 for(i=1;i<=n;i++) 103 { 104 scanf("%d",&Tree[0][i]); 105 Sort[i]=Tree[0][i]; 106 } 107 sort(Sort+1,Sort+1+n); 108 build(1,n,0); 109 printf("Case #%d:\n",qq); 110 while(m--) 111 { 112 scanf("%d%d%d%d",&l,&r,&a,&b); 113 hxl=query(1,n,l,r,0,1); 114 if(a<=hxl) hxl=1; //对临界条件的判断。如果A就是最小的,木有下届 115 else 116 { 117 hxl=EF1(l,r,a,n); 118 hxl++; 119 } 120 tom=query(1,n,l,r,0,r-l+1); 121 if(b>=tom) tom=r-l+1; //如果B是该区间[l,r]最大的,显然木有上届 122 else 123 { 124 tom=EF2(l,r,b,n); 125 tom--; 126 } 127 hxl=tom-hxl+1; 128 printf("%d\n",hxl); 129 } 130 } 131 } 132 return 0; 133 }