杭电 4417(路过的大牛看看差距差距在哪里,为什么我的超时(超过 1000ms),别人的300ms)
2012-09-24 17:24
337 查看
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; const int MAXN=100010; int tree[30][MAXN];//表示每层每个位置的值 int sorted[MAXN];//已经排序的数 int toleft[30][MAXN];//toleft[p][i]表示第i层从1到i有多少个数分入左边 void build(int l,int r,int dep) { if(l==r)return; int mid=(l+r)>>1; int same=mid-l+1;//表示等于中间值而且被分入左边的个数 for(int i=l;i<=r;i++) if(tree[dep][i]<sorted[mid]) same--; int lpos=l; int rpos=mid+1; for(int i=l;i<=r;i++) { if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边 tree[dep+1][lpos++]=tree[dep][i]; else if(tree[dep][i]==sorted[mid]&& same>0) { tree[dep+1][lpos++]=tree[dep][i]; same--; } else //比中间值大分入右边 tree[dep+1][rpos++]=tree[dep][i]; toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数 } build(l,mid,dep+1); build(mid+1,r,dep+1); } //查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间 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];//[l,r]中位于左边的个数 if(cnt>=k) { //L+要查询的区间前被放在左边的个数 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 solve(int n,int s,int t,int h) { int ans=0; int l=1; int r=(t-s)+1; int mid; while(l<=r) { mid=(l+r)>>1; int temp=query(1,n,s,t,0,mid); if(temp<=h) { ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; int n,m; int s,t,h; scanf("%d",&T); int iCase=0; while(T--) { iCase++; scanf("%d%d",&n,&m); memset(tree,0,sizeof(tree));//这个必须 for(int i=1;i<=n;i++)//从1开始 { scanf("%d",&tree[0][i]); sorted[i]=tree[0][i]; } sort(sorted+1,sorted+n+1); build(1,n,0); printf("Case %d:\n",iCase); while(m--) { scanf("%d%d%d",&s,&t,&h); s++; t++; printf("%d\n",solve(n,s,t,h)); } } return 0; } #include<stdio.h> #include<stdlib.h> #include<string.h> //#include <iostream> //using namespace std ; const int MAXN = 100010 ; int data[30][MAXN], sorted[MAXN], toleft[30][MAXN] ; int cmp(const void *a, const void *b){ return *(int *)a < *(int *)b ? -1 : 1 ; } void build(int l, int r, int d){ if(l==r) return ; int i ; int m = (l + r) >> 1 ; int ls = m - l + 1 ; //用来标记和中间值m相等的,且分到左孩子的数的个数。 //初始时,假定当前区间[l,r]有mid-l+1个和m 相等。 //先踢掉比中间值小的,剩下的就是要插入到左边的*/ for(i=l; i<=r; i++) if(data[d][i]<sorted[m]) ls -- ; //踢掉比中间值小的 int lp = l ; int rp = m + 1 ; for(i=l; i<=r; i++){ if(i==l) toleft[d][i] = 0 ; //// 初始一个子树。 else toleft[d][i] = toleft[d][i-1] ; //// 初始区间下一个节点。 /* 如果大于,肯定进入右孩子,否则,判断是否还有相等的应该进入左孩子的, 没有,就直接进入右孩子,否则进入左孩子*/ if(data[d][i]<sorted[m]){ toleft[d][i]++; data[d+1][lp++] = data[d][i] ; }else if(data[d][i]>sorted[m]) data[d+1][rp++] = data[d][i] ; else{ //考虑相等 if(ls){ // 相等分到做孩子的数目>0 ls -- ; toleft[d][i]++ ; data[d+1][lp++] = data[d][i] ; }else data[d+1][rp++] = data[d][i] ; } } build(l, m, d+1) ; build(m+1, r, d+1) ; } int query(int L, int R, int k, int l, int r, int d){ //在[L,R]区间寻找小于第k 的元素,总区间[l,r] if(L==R) return data[d][L] ; int m = (l + r) >> 1 ; int lLR, llL, rLR, rlL ; if(L==l){ lLR = toleft[d][R] ; //lLR 左边小于第k个元素的数量 llL = 0 ; //llL 记录区间[lft, a-1)中计入左孩子的元素的个数。 }else{ lLR = toleft[d][R] - toleft[d][L-1] ; // llL = toleft[d][L-1] ; } int nl, nr ; if(lLR>=k){ nl = l + llL ; //记录区间[L, R]中进入左孩子的元素的个数。 nr = l + lLR + llL - 1 ; // return query(nl, nr, k, l, m, d+1) ; }else{ rlL = L - l - llL ; //表示[L, R] 中分到右孩子的个数 rLR = R - L + 1 - lLR ; //表示[lft, a-1]中分到右孩子的个数 nl = m + 1 + rlL ; nr = m + rlL + rLR ; return query(nl, nr, k-lLR, m+1, r, d+1) ; } } int solve(int n,int s,int t,int hight) { int ans=0; int l=1; int r=(t-s)+1; int mid; while(l<=r) { mid=(l+r)>>1; int temp=query(s,t,mid,1,n,0); if(temp<=hight) { ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main(){ int n, m, i, j, l, r, k,t,Case=1; scanf("%d",&t); while(t--) { memset(data,0,sizeof(data)); scanf("%d%d",&n,&m); for(i=1; i<=n; i++){ scanf("%d",&data[0][i] ); sorted[i] = data[0][i] ; } qsort(sorted+1, n, sizeof(int), cmp) ; build(1, n, 0); printf("Case %d:\n",Case++); while(m--){ scanf("%d%d%d", &l, &r, &k) ; //printf("%d\n",query(l, r, k, 1, n, 0)) ; printf("%d\n",solve(n,l+1,r+1,k)); } } return 0 ; }
相关文章推荐
- 同样是程序员,看看你和别人差距在哪里
- 对待棘手bug,新手与大牛的差距在哪里?
- 对待棘手bug,新手与大牛的差距在哪里?
- 谈-我和别人的差距在哪里?
- 为什么运行NOVA命令总要报一个DEBUG,没找到原因,路过的大侠一起看看啊
- 非985大学生, 你和别人的差距在哪里?(转)
- 如何减小与“大牛”的差距
- 第十二章 当别人叫你往前站的时候,先看看是否有子弹飞来
- 如何减少与大牛的差距
- 小心啊,这样的程序已经好了,但调试的时候数据是没有更新的啊~为什么,看看我的悲惨经历了
- 看看别人十年软件开发后学到了什么
- 看看别人的代码风格吧
- 【随想】_与技术无关_为什么机会总是别人的?
- 电脑有点卡为什么别人的好?
- “菜鸟”程序员和“大神”程序员差距在哪里
- 哪里有WM的开发源码看看学习一下?
- 如何减小与“大牛”的差距
- [翻译]为什么redux会超过flux?
- 看看别人实现的投影触控技术
- 为什么别人比你赚得多?