题意:
给一列数..若干个询问..问(l,r,h)...在[l,r]范围内..有多少个数小于等于h....
题解:
二分第k小..用划分树 查找第k小是哪个数..就可以把每个提问的答案找出来了...
读入数据后..忘记要L++,R++了..浪费了好多时间..终于把划分树的最终模板敲定了...去年网络赛的时候..看到这题.就想到了kth number..马上去找了个kth number的代码..加个二分.就水过了...当时运气也好..万一找打那份代码不能解决相同元素就要跪烂了...真正要自己来写前面的划分树.确实没这么轻松...
今天队内赛的一题和这道一模一样...改了一下提交..居然超时了..应该是spoj的机器太挫了吧...看来还是得用线段树(树状数组)来离线处理了..
Program:
#include<iostream> #include<stdio.h> #include<string.h> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #include<algorithm> #define ll long long #define eps 1e-5 #define oo 1000000007 #define pi acos(-1.0) #define MAXN 100005 using namespace std; int tree[21][MAXN],num[21][MAXN],sorted[MAXN]; void built(int l,int r,int t) { if (l==r) return; int i,x,y,mid=r+l>>1,m=mid-l+1; x=l,y=mid+1; for (i=l;i<=r;i++) if (sorted[i]<sorted[mid]) m--; for (i=l;i<=r;i++) { num[t][i]=num[t][i-1]; if (tree[t][i]==sorted[mid]) { if (m) tree[t+1][x++]=tree[t][i],num[t][i]++,m--; else tree[t+1][y++]=tree[t][i]; }else if (tree[t][i]<sorted[mid]) tree[t+1][x++]=tree[t][i],num[t][i]++; else tree[t+1][y++]=tree[t][i]; } built(l,mid,t+1),built(mid+1,r,t+1); } int query(int L,int R,int k,int l,int r,int t) { if (L==R) return tree[t][L]; int ltoL,LtoR,mid=l+r>>1; ltoL=num[t][L-1]-num[t][l-1],LtoR=num[t][R]-num[t][L-1]; if (LtoR>=k) return query(l+ltoL,l+ltoL+LtoR-1,k,l,mid,t+1); int b=L-l-ltoL,bb=R-L+1-LtoR; return query(mid+b+1,mid+b+bb,k-LtoR,mid+1,r,t+1); } int main() { int T,cases,i,n,m; scanf("%d",&T); for (cases=1;cases<=T;cases++) { scanf("%d%d",&n,&m); memset(num,0,sizeof(num)); for (i=1;i<=n;i++) scanf("%d",&tree[0][i]),sorted[i]=tree[0][i]; sort(sorted+1,sorted+1+n); built(1,n,0); printf("Case %d:\n",cases); while (m--) { int L,R,H,l,r,mid; scanf("%d%d%d",&L,&R,&H); L++,R++; l=0,r=R-L+2; while (r-l>1) { mid=r+l>>1; if (query(L,R,mid,1,n,0)<=H) l=mid; else r=mid; } printf("%d\n",l); } } return 0; }