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
Case #1: 13 7 3 6 9
这题描述是求给定区间(s,t)求比a大且比b小的数
转换求a和b在区间的大小在相减就行我用划分树做的1280ms听说用主席树更快
ACcode:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 100100 using namespace std; int tree[20][maxn]; int sorted[maxn]; int toleft[20][maxn]; void build(int l,int r,int d){ if(l == r) return; int mid = (l + r) >> 1; int same = mid - l + 1; for(int i = l; i <= r; i++) if(tree[d][i] < sorted[mid]) same --; int lpos = l,rpos = mid + 1; for(int i = l; i <= r; i++){ if(tree[d][i] < sorted[mid]){ toleft[d][i] = toleft[d][i - 1] + 1; tree[d + 1][lpos++] = tree[d][i]; } else if(tree[d][i] == sorted[mid] && same > 0){ same --; toleft[d][i] = toleft[d][i - 1] + 1; tree[d + 1][lpos++] = tree[d][i]; } else{ toleft[d][i] = toleft[d][i - 1]; tree[d + 1][rpos++] = tree[d][i]; } } build(l,mid,d + 1); build(mid + 1,r,d + 1); } int query(int L,int R,int l,int r,int dep,int k){ if(l==r)return tree[dep][l]; int mid=(L+R)>>1; int cnt=toleft[dep][r]-toleft[dep][l-1]; if(cnt>=k){ int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; int newr=newl+cnt-1; return query(L,mid,newl,newr,dep+1,k); } else { int newr=r+toleft[dep][R]-toleft[dep][r]; int newl=newr-(r-l-cnt); return query(mid+1,R,newl,newr,dep+1,k-cnt); } } int main(){ int loop,n,m,cnt=1; scanf("%d",&loop); while(loop--){ memset(tree,0,sizeof(tree)); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%d",&tree[0][i]); sorted[i]=tree[0][i]; } sort(sorted+1,sorted+1+n); build(1,n,0); int s,t,a,b; printf("Case #%d:\n",cnt++); while(m--){ scanf("%d%d%d%d",&s,&t,&a,&b); int low,big,l,r; l=1;r=t-s+2; while(l<r){ int mid=(l+r)>>1; int tmp=query(1,n,s,t,0,mid); if(a>tmp) l=mid+1; else r=mid; } low=l; l=1;r=t-s+2; while(l<r){ int mid=(l+r)>>1; int tmp=query(1,n,s,t,0,mid); if(b>=tmp) l=mid+1; else r=mid; } big=l; cout<<big-low<<'\12'; } } } /* 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 */