今天在大白(挑战程序设计)上重新看了一遍分块数组相关的内容,虽然以前看过了,也做过相关的题目,但是总感觉只知道思想,自己不敢实现,今天把上面的例题照着敲了敲,也算加深了印象吧。
例题:POJ2104和HDU2665
这两个是题都是求区间第K大,只不过HDU上数据强并且时间限制少了点。
以前以为平方分割求这种题还挺快的,没想到啊。。在POJ 11000+ms勉强水过,在HDU无情T掉。
不过归并树倒是有些出乎我意料的快,POJ 6000+ms,HDU 3500+ms
归并树之所以叫归并树是因为这一整棵树刚好是归并排序的完整再现。
今天除了温习了这两种数据结构,新收获是get了库函数merge的用法,以及!以后在这两个OJ上交题千万注意的一
点 ! 当你交C++ T了的时候不妨交一发G++试一试,极大可能会有惊喜,上面这两种算法我交C++都是TLE,很气。
PS:区间第K大一类的问题好像是主席树裸题,看人家400+ms轻松跑过的题而我要跑11000+ms,真的是欲哭无泪啊,改天膜拜一下主席树回来再战!
poj 的块状数组代码:
#include<iostream> #include<algorithm> #include<vector> #include<stdio.h> #include<math.h> using namespace std; const int MAXN=100010; const int B=1000; vector<int>bucket[MAXN]; int a[MAXN],tmp[MAXN]; void init(int n) { for(int i=0;i<n;i++) { bucket[i/B].push_back(a[i]); tmp[i]=a[i]; } sort(tmp,tmp+n); for(int i=0;i<n/B;i++) sort(bucket[i].begin(),bucket[i].end()); } int check(int mid,int tl,int tr) { int x=tmp[mid]; int cnt=0; //区间两端多出的部分 while(tl < tr && tl % B) if(a[tl++] <= x) cnt++; while(tl < tr && tr % B) if(a[--tr] <= x) cnt++; //对每一个桶进行计算 while(tl < tr) { int b = tl / B; cnt += upper_bound(bucket[b].begin(), bucket[b].end(),x) - bucket[b].begin(); tl += B; } return cnt; } int solve(int L,int R,int K,int n) { int l=0,r=n-1,mid; while(l<=r) { mid=(l+r)>>1; if(check(mid,L,R+1) >= K) r = mid-1; else l = mid+1; } //cout<<l<<" "<<r<<endl; return tmp[r+1]; } int main() { int n,m,l,r,k,T; //cin>>T; //while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",a+i); init(n); while(m--) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",solve(l-1,r-1,k,n)); } } }
HDU的归并树:
#include<iostream> #include<stdio.h> #include<algorithm> #include<vector> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; const int MAXN = 100010; int a[MAXN]; vector<int>tree[MAXN<<2]; void build(int l,int r,int rt) { if(l==r) { tree[rt].push_back(a[l]); return ; } int mid=(l+r)>>1; build(lson); build(rson); tree[rt].resize(r-l+1); merge(tree[rt<<1].begin(),tree[rt<<1].end(),tree[rt<<1|1].begin(),tree[rt<<1|1].end(),tree[rt].begin()); } int query(int L,int R,int x,int l,int r,int rt) { if(L<=l&&r<=R) { return upper_bound(tree[rt].begin(),tree[rt].end(),x)-tree[rt].begin(); } int mid=(l+r)>>1,sum=0; if(L<=mid) sum+=query(L,R,x,lson); if(R>mid) sum+=query(L,R,x,rson); return sum; } int tmp[MAXN]; int solve(int L,int R,int k,int n) { int l=1,r=n,mid; while(l<=r) { mid=(l+r)>>1; if(query(L,R,tmp[mid],1,n,1) >= k) r=mid-1; else l=mid+1; } return tmp[r+1]; } int main() { int n,m,l,r,k; int T; cin>>T; while(T--) { cin>>n>>m; for(int i=1;i<=n;i++) scanf("%d",a+i),tmp[i]=a[i]; build(1,n,1); sort(tmp+1,tmp+n+1); while(m--) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",solve(l,r,k,n)); } for(int i=0;i<MAXN*4;i++) tree[i].clear(); } }